001/* 002 * #%L 003 * Netarchivesuite - common 004 * %% 005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University Library, 006 * the National Library of France and the Austrian National Library. 007 * %% 008 * This program is free software: you can redistribute it and/or modify 009 * it under the terms of the GNU Lesser General Public License as 010 * published by the Free Software Foundation, either version 2.1 of the 011 * License, or (at your option) any later version. 012 * 013 * This program is distributed in the hope that it will be useful, 014 * but WITHOUT ANY WARRANTY; without even the implied warranty of 015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 016 * GNU General Lesser Public License for more details. 017 * 018 * You should have received a copy of the GNU General Lesser Public 019 * License along with this program. If not, see 020 * <http://www.gnu.org/licenses/lgpl-2.1.html>. 021 * #L% 022 */ 023package dk.netarkivet.common.distribute; 024 025import java.io.ObjectInputStream; 026import java.io.ObjectOutputStream; 027import java.io.Serializable; 028 029import dk.netarkivet.common.CommonSettings; 030import dk.netarkivet.common.exceptions.ArgumentNotValid; 031import dk.netarkivet.common.exceptions.IOFailure; 032import dk.netarkivet.common.exceptions.UnknownID; 033import dk.netarkivet.common.utils.Settings; 034import dk.netarkivet.common.utils.SystemUtils; 035 036/** 037 * A class for representing the names of JMS queues. 038 */ 039@SuppressWarnings({"serial"}) 040public class ChannelID implements Serializable { 041 042 /** 043 * The name of the enviroment in which this process is running. It is used for prefixing all ChannelIDs. An example 044 * value is "PROD". 045 */ 046 private final String environmentName = Settings.get(CommonSettings.ENVIRONMENT_NAME); 047 048 /** 049 * application instance id is a setting for an application's identification as a specific process on a given 050 * machine. An example value is "BAONE" Note that it is set to uppercase in order to ensure that a channel name only 051 * has uppercase characters. 052 */ 053 private static final String applicationInstanceId = Settings.get(CommonSettings.APPLICATION_INSTANCE_ID) 054 .toUpperCase(); 055 056 /** 057 * application instance id is a setting for an application's identification as a specific process on a given 058 * machine. An example value is "BAONE". 059 */ 060 private static final String applicationAbbreviation = getApplicationAbbreviation(Settings 061 .get(CommonSettings.APPLICATION_NAME)); 062 063 /** 064 * Constants to make the semantics of parameters to our name constructors more explicit. 065 */ 066 public static final String COMMON = "COMMON"; 067 public static final boolean INCLUDE_IP = true; 068 public static final boolean NO_IP = false; 069 public static final boolean INCLUDE_APPLINST_ID = true; 070 public static final boolean NO_APPLINST_ID = false; 071 public static final boolean TOPIC = true; 072 public static final boolean QUEUE = false; 073 074 /** 075 * A ChannelID is identified by its name. It has one bit of state information: is it a queue or a topic? 076 */ 077 private String name; 078 079 /** 080 * Constructor of channel names. The constructor is package private because we should never use any channels except 081 * the ones constructed by our friend Channels.java 082 * 083 * @param appPref The prefix used for the applications listening to the channel. 084 * @param replicaId Name of the replica, or ChannelID.COMMON if channel shared by all replicas. 085 * @param useNodeId Whether that IP address of the local node should be included in the channel name. 086 * @param useAppInstId Whether application instance id from settings should be included in the channel name. 087 * @param isTopic Whether the Channel is a Topic or a Queue. 088 * @throws UnknownID if looking up the local IP number failed. 089 */ 090 public ChannelID(String appPref, String replicaId, boolean useNodeId, boolean useAppInstId, boolean isTopic) { 091 this.name = constructName(appPref, replicaId, useNodeId, useAppInstId, isTopic); 092 } 093 094 /** 095 * Constructs a channel name according to the specifications of channels in the NetarchiveSuite Developer Manual. 096 * 097 * @param appPref The prefix used for the applications listening to the channel. 098 * @param replicaId Id of the replica, or ChannelID.COMMON if channel common to all bitarchive replicas. 099 * @param useNodeId Whether that IP address of the local node should be included in the channel name. 100 * @param useAppInstId Whether application instance id from settings should be included in the channel name. 101 * @param isTopic If true, the channel is a Topic, else it is a Queue 102 * @return The properly concatenated channel name. 103 * @throws UnknownID if looking up the local IP number failed. 104 */ 105 private String constructName(String appPref, String replicaId, boolean useNodeId, boolean useAppInstId, 106 boolean isTopic) { 107 String userId = environmentName; 108 String id = ""; 109 if (useNodeId) { 110 // Replace the '.' in the IP-address with '_' 111 id = SystemUtils.getLocalIP().replace('.', '_'); 112 if (useAppInstId) { 113 id += Channels.CHANNEL_PART_SEPARATOR + applicationAbbreviation; 114 if (!applicationInstanceId.isEmpty()) { 115 id += (Channels.CHANNEL_PART_SEPARATOR + applicationInstanceId); 116 } 117 } 118 } 119 120 String resultingName = userId + Channels.CHANNEL_PART_SEPARATOR + replicaId + Channels.CHANNEL_PART_SEPARATOR 121 + appPref; 122 if (!id.isEmpty()) { 123 resultingName += Channels.CHANNEL_PART_SEPARATOR + id; 124 } 125 if (isTopic) { 126 resultingName += Channels.CHANNEL_PART_SEPARATOR + "TOPIC"; 127 } 128 return resultingName; 129 } 130 131 /** 132 * Getter for the channel name. 133 * 134 * @return The name of the channel referred to by this object. 135 */ 136 public String getName() { 137 return name; 138 } 139 140 /** 141 * Pretty-printer. 142 * 143 * @return a nice String representation of the ChannelID. 144 */ 145 public String toString() { 146 return Channels.isTopic(name) ? ("[Topic '" + name + "']") : ("[Queue '" + name + "']"); 147 } 148 149 /** 150 * Method used by Java deserialization. Our coding guidelines prescribes that this method should always be 151 * implemented, even if it only calls the default method: 152 * http://kb-prod-udv-001.kb.dk/twiki/bin/view/Netarkiv/ImplementeringOgTestAfSerializable See also 153 * "Effective Java", pages 219 and 224. 154 * 155 * @param ois the ObjectInputStream used to read in the object 156 * @throws IOFailure if Java could not deserialize the object. 157 */ 158 private void readObject(ObjectInputStream ois) { 159 try { 160 ois.defaultReadObject(); 161 } catch (Exception e) { 162 throw new IOFailure("Standard deserialization of ChannelID failed.", e); 163 } 164 } 165 166 /** 167 * Method used by Java serialization. Our coding guidelines prescribes that this method should always be 168 * implemented, even if it only calls the default method: 169 * http://kb-prod-udv-001.kb.dk/twiki/bin/view/Netarkiv/ImplementeringOgTestAfSerializable See also 170 * "Effective Java", pages 219 and 224. 171 * 172 * @param oos the ObjectOutputStream used to serialize the object. 173 * @throws IOFailure if Java could not serialize the object. 174 */ 175 private void writeObject(ObjectOutputStream oos) { 176 try { 177 oos.defaultWriteObject(); 178 } catch (Exception e) { 179 throw new IOFailure("Standard serialization of ChannelID failed.", e); 180 } 181 } 182 183 /** 184 * Implements equality check for ChannelIDs. Useful when these are used as indexes in Java collections, for 185 * instance. 186 * 187 * @param o The object to compare this object with. 188 * @return Whether o and this should be considered the same ChannelID. 189 */ 190 public boolean equals(Object o) { 191 if (this == o) { 192 return true; 193 } 194 if (!(o instanceof ChannelID)) { 195 return false; 196 } 197 final ChannelID channelID = (ChannelID) o; 198 if (!name.equals(channelID.name)) { 199 return false; 200 } 201 return true; 202 } 203 204 /** 205 * Computes a hash code based on the channel name and whether it is a topic. 206 * 207 * @return A hash code for this object. 208 */ 209 public int hashCode() { 210 int result; 211 result = name.hashCode(); 212 return result; 213 } 214 215 /** 216 * Finds abbreviation for an application name. The abbreviation is only calculated from the application name without 217 * path. It is made from the uppercase letters in the name. 218 * 219 * @param applName application name with full path 220 * @return abbreviation for given application name. 221 */ 222 private static String getApplicationAbbreviation(String applName) { 223 ArgumentNotValid.checkNotNull(applName, "applName"); 224 // Strip path from name 225 String[] p = applName.split("[.]"); 226 if (p.length <= 0) { 227 return ""; 228 } 229 String shortName = p[p.length - 1]; 230 // put uppercase letters into abbr 231 String abbr = ""; 232 for (int i = 0; i < shortName.length(); i++) { 233 if (Character.isUpperCase(shortName.charAt(i))) { 234 abbr += shortName.substring(i, i + 1); 235 } 236 } 237 // return found abbreviation 238 return abbr; 239 } 240 241}