0001: /* ----- BEGIN LICENSE BLOCK -----
0002: * Version: MPL 1.1
0003: *
0004: * The contents of this file are subject to the Mozilla Public License Version
0005: * 1.1 (the "License"); you may not use this file except in compliance with
0006: * the License. You may obtain a copy of the License at
0007: * http://www.mozilla.org/MPL/
0008: *
0009: * Software distributed under the License is distributed on an "AS IS" basis,
0010: * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
0011: * for the specific language governing rights and limitations under the
0012: * License.
0013: *
0014: * The Original Code is the DataShare server.
0015: *
0016: * The Initial Developer of the Original Code is
0017: * Ball Aerospace & Technologies Corp, Fairborn, Ohio
0018: * Portions created by the Initial Developer are Copyright (C) 2001
0019: * the Initial Developer. All Rights Reserved.
0020: *
0021: * Contributor(s): Charles Wood <cwood@ball.com>
0022: *
0023: * ----- END LICENSE BLOCK ----- */
0024: /* RCS $Id: DataShareServer.java,v 1.12 2002/02/21 13:20:12 lizellaman Exp $
0025: * $Log: DataShareServer.java,v $
0026: * Revision 1.12 2002/02/21 13:20:12 lizellaman
0027: * correct problem of not getting history finished object
0028: *
0029: * Revision 1.11 2002/02/20 14:15:11 lizellaman
0030: * changes to improve history retrieval
0031: *
0032: * Revision 1.10 2002/02/11 20:02:10 lizellaman
0033: * Correct problem with retreiving non-cached EJBs, and update version/date
0034: *
0035: * Revision 1.9 2002/02/06 18:57:11 lizellaman
0036: * Added the database deletion of Sessions if they have no channels that were saving data.
0037: *
0038: * Revision 1.8 2002/02/04 19:34:57 lizellaman
0039: * correct spelling of privilege
0040: *
0041: * Revision 1.7 2002/02/04 13:51:39 lizellaman
0042: * Remove all references to past product names (or)
0043: * Add PublicAPI for creating Rendezvous Sessions
0044: *
0045: * Revision 1.6 2002/01/29 20:50:17 lizellaman
0046: * Added LoggingInterface, modified the PropertiesInterface implementation
0047: *
0048: * Revision 1.5 2002/01/22 15:05:53 lizellaman
0049: * make admin attribute for clients default to false (was true)
0050: *
0051: * Revision 1.4 2002/01/20 23:26:29 lizellaman
0052: * add command line parameter that causes an plain DataShareObject to be sent to 'inactive' TCP connections after X milliseconds on inactivity
0053: *
0054: * Revision 1.3 2002/01/03 03:37:36 lizellaman
0055: * periodic update of changes I have made
0056: *
0057: * Revision 1.2 2001/10/31 16:12:15 lizellaman
0058: * changed to look for functions-file as file and as resource before giving up
0059: *
0060: * Revision 1.1.1.1 2001/10/23 13:37:18 lizellaman
0061: * initial sourceforge release
0062: *
0063: */
0064:
0065: package org.datashare;
0066:
0067: import java.net.SocketPermission;
0068: import java.net.InetAddress;
0069: import java.io.ObjectOutputStream;
0070: import java.io.ByteArrayOutputStream;
0071: import java.io.BufferedOutputStream;
0072: import java.io.BufferedReader;
0073: import java.io.FileReader;
0074: import java.io.IOException;
0075: import java.io.FileNotFoundException;
0076: import java.util.StringTokenizer;
0077: import java.util.Vector;
0078: import java.util.List;
0079: import java.util.LinkedList;
0080: import java.util.Collections;
0081: import java.util.Enumeration;
0082: import java.util.Hashtable;
0083: import java.util.Properties;
0084: import java.util.GregorianCalendar;
0085: import java.util.Date;
0086: import java.lang.reflect.Method;
0087: import java.lang.reflect.Field;
0088: import javax.swing.tree.DefaultMutableTreeNode;
0089:
0090: import org.datashare.objects.ChannelDescription;
0091: import org.datashare.objects.ChannelDescriptionArray;
0092: import org.datashare.objects.RegistrationInfo;
0093: import org.datashare.objects.ServerInfo;
0094: import org.datashare.objects.DataShareConnectionDescriptor;
0095: import org.datashare.objects.DataShareObject;
0096: import org.datashare.objects.ClientSessionInfo;
0097: import org.datashare.objects.ActivateConnectionObject;
0098: import org.datashare.objects.CreateSessionRequest;
0099: import org.datashare.objects.RegisterTreeListener;
0100: import org.datashare.objects.RequestTree;
0101: import org.datashare.objects.TreeObject;
0102: import org.datashare.objects.JoinSession;
0103: import org.datashare.objects.DeleteSession;
0104: import org.datashare.objects.DisconnectConsumer;
0105: import org.datashare.objects.InstantMsgData;
0106: import org.datashare.objects.RequestHistory;
0107: import org.datashare.objects.RequestFunctionInfo;
0108: import org.datashare.objects.HistoryCountObject;
0109: import org.datashare.objects.TokenRequestObject;
0110: import org.datashare.objects.ControlServerObject;
0111: import org.datashare.objects.RequestSessionNames;
0112: import org.datashare.objects.SessionNames;
0113: import org.datashare.objects.RequestFunctionsInSession;
0114: import org.datashare.objects.FunctionsInSession;
0115: import org.datashare.objects.ServerStatusObject;
0116: import org.datashare.plugins.LoggingManager.LoggingAdapter;
0117: import org.datashare.plugins.PropertiesManager.PropertiesManagerAdapter;
0118:
0119: /**
0120: * For now, a limitation of this design is that it uses a separate port for each Session and Channel.
0121: * This will be changed in the future so that better 'in band' information will let a single server port
0122: * serve more that one purpose. Trying to keep it simple for now.
0123: * @date March 01, 2001
0124: * @author Charles Wood
0125: * @version 1.0
0126: */
0127: public class DataShareServer implements DataReceiverInterface,
0128: TreeViewServerInterface, FifoConsumer {
0129: // these are set to indicate the availability of the pluggable interfaces we can use
0130: static boolean persistenceAdapterFound = false; // true if we have an implemention for the PersistenceInterface
0131: //static boolean loggingAdapterFound=false; // not needed, we always have a LoggingInterface
0132: static boolean logInAdapterFound = false; // true if we have an implementation for the LogInInterface
0133: static boolean serviceAdapterFound = false; // true if we have an implementation for the ServiceInterface
0134: //static boolean propertiesManagerAdapterFound=false; // true if we have an implementation for the PropertiesMangerInterface
0135:
0136: static String persistenceInterfaceClassName; // loaded from properties
0137: static String propertiesInterfaceClassName; // loaded from properties
0138: static String logInInterfaceClassName; // loaded from properties
0139: static String loggingInterfaceClassName; // loaded from properties
0140: static String serviceInterfaceClassName; // loaded from properties
0141:
0142: static PersistenceInterface persistenceInterface = null; // will be set to the class that implements the persistenceInterface
0143: static PropertiesInterface propertiesInterface = null; // optional pluggable properties manager, run after generic one
0144: static ServiceInterface serviceInterface = null;
0145: static LoggingInterface loggingInterface = new LoggingAdapter();
0146: static LogInInterface logInInterface = null;
0147:
0148: static String propertiesFile; // loaded from properties
0149:
0150: /**
0151: * this is where we will store our configurable data, can be overwritten by
0152: * Java defines. May also be overwritten by command line options. Normal
0153: * SystemProperties may be added into this if a propertiesManager is loaded.
0154: */
0155: static Hashtable properties = new Hashtable();
0156:
0157: /**
0158: * true if we will be using a database to save info about DataShare objects. Must be false
0159: * if useDatabase is false. Note that individual channels have their own control over saving data.
0160: * This value is set at startup and must not change. Cannot be true if useDatabase is false. If useDatabase
0161: * is true and this is false, then information about Clients and Sessions (and their associated info) will
0162: * not be saved. This can be initialized as a command line parameter.
0163: */
0164: static protected boolean persistData;
0165:
0166: /**
0167: * true if we have access to a database. The database by default is used for client accounts, saving info
0168: * about active Clients and Sessions, etc. This can be initialized as a command line parameter.
0169: */
0170: static private boolean useDatabase /*inAContainer*/;
0171:
0172: /**
0173: * true if we have access to a database and should try to authenticate clients. Must be false
0174: * if useDatabase is false. This can be initialized as a command line parameter.
0175: */
0176: static private boolean authenticatingClients = true; // set to true if we should try to find userproxy (this feature is untested)
0177:
0178: static TcpSocketServer commandStatusServerThread = null;
0179:
0180: // command line parameters...
0181: static private int firstPort;
0182: static private int lastPort;
0183: static private boolean debug = true; // this value will be used until we read in a new value from commandLine/file
0184: static private int commandStatusPort;
0185: static boolean showArchivedSessionsToAdmin; // if true, admin clients will see closed sessions, must be false if useDatabase is false
0186: static String channelTypesFile; // set to file on server that contains information about functions
0187: static String multiCastIPaddress; // set to a valid IP Multicast address
0188: static int TCPSocketReadTimeout; // used to set timeouts on TCP reads
0189: static int currentPort;
0190:
0191: /**
0192: * This hashtable is used to keep up with who is connected to the commandStatus
0193: * Connection. It stores SocketAdapters, one for each client who is connected
0194: * on the commandStatus Connection, keyed by the clientKeyValue. Entries are
0195: * removed when we lose the commandStatus connection to a client (see connectionLost() );
0196: */
0197: static private Hashtable commandStatusSocketHandlers = new Hashtable();
0198:
0199: /**
0200: * contains SessionInfo objects, keyed by the Session name (active sessions names are unique), one
0201: * for every Session on the Server.
0202: */
0203: static private Hashtable sessionTable = new Hashtable();
0204:
0205: /**
0206: * contains all SpecialClients, keyed by client names (unique, converted to lowercase), one for every Client,
0207: * used to check for unique names, must be in table to create/delete Sessions and show up as a Consumer,
0208: */
0209: static private Hashtable specialClientTable = new Hashtable();
0210:
0211: /**
0212: * This is a Hashtable of ThreadedSockets that have been opened on the server's
0213: * CommandStatus connection. These sockets have not been 'registered', i.e. the
0214: * client has not yet sent its RegistrationInfo object to the server. Once registered,
0215: * these client entries will be removed from this table and put into the clients table.
0216: * This table contains ThreadedSockets indexed by their keyValues. Note that clients
0217: * that will be viewing History Data will be in this table because their connections
0218: * will not have been activated.
0219: */
0220: static private Hashtable connections = new Hashtable();
0221:
0222: /**
0223: * this will contain all the DataReceiverAdapters that have been created (one for each channel)
0224: */
0225: static private Vector allDataReceiverAdapters = new Vector();
0226:
0227: /**
0228: * this is a LIFO Queue that will be used to create our data from a seperate Thread.
0229: * The PersistDataQueueObject is put in the Queue and fully describes the EJB to be created.
0230: */
0231: static private FifoQueue persistDataQueue = null;
0232:
0233: static private final String serverStartTime = new GregorianCalendar()
0234: .getTime().toString();
0235: static private String serverVersion = null;
0236: static private String serverVersionHtml = null;
0237: static private String myClientKeyValue = null;
0238: static private InetAddress myIPAddress = null;
0239: static private DataShareConnectionDescriptor commandStatusDescriptor = null;
0240:
0241: /**
0242: * This info is loaded from the configuration files and contains all we need to know
0243: * about what type functions will be available for collaboration.
0244: */
0245: static private ChannelDescriptionArray channelDescriptionArray = null;
0246:
0247: static TreeView treeView = null;
0248:
0249: static private boolean alreadyShuttingDown = false; // so we don't call shutdown procedure more than once
0250: static String serverInfoString = "";
0251:
0252: /**
0253: * Constructor, creates our DataShare server
0254: */
0255: public DataShareServer() // throws RemoteException
0256: {
0257: try {
0258: // SessionUtilities.setLoggingInterface(loggingInterface); // handled by SessionUtilities 'static'
0259: myIPAddress = InetAddress.getLocalHost();
0260: loggingInterface.debugMsg(loggingInterface.DEBUG,
0261: loggingInterface.NETWORK, "My IP address is "
0262: + myIPAddress.getHostAddress());
0263: SessionUtilities
0264: .setServername(myIPAddress.getHostAddress());
0265: } catch (Exception e) {
0266: loggingInterface.debugMsg(loggingInterface.ERROR,
0267: loggingInterface.NETWORK,
0268: "Problems getting my IP address...");
0269: loggingInterface.logException(LoggingInterface.ERROR, e);
0270: this .shutDownConnectionsAndThreads();
0271: }
0272: }
0273:
0274: public static void
0275: main(String args[])
0276: {
0277: SessionUtilities.setVerbose(debug);
0278: DataShareServer dataShareServer = new DataShareServer();
0279: dataShareServer.initializeValues(args); // will use PropertiesManager to set attribute values
0280: SessionUtilities.setVerbose(debug); // may have changed
0281: dataShareServer.loadInterfaces(); // find the other interfaces and load if found
0282:
0283: try{
0284: if(serviceAdapterFound)
0285: serviceInterface.initialize(dataShareServer);
0286:
0287: if(useDatabase)
0288: persistenceInterface.initialize();
0289:
0290: // debug to print out the values of our properties
0291: try{
0292: for(Enumeration enum = properties.keys(); enum.hasMoreElements();)
0293: {
0294: String name = (String)enum.nextElement();
0295: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.GENERALSTATUS,
0296: "Name = " + name + ", Value = " + properties.get(name));
0297: }
0298: }
0299: catch(Exception e)
0300: {
0301: loggingInterface.debugMsg(loggingInterface.WARNING,loggingInterface.GENERALSTATUS,
0302: "Problems getting Properties..." + e);
0303: //e.printStackTrace();
0304: }
0305:
0306: dataShareServer.getChannelDescriptionsFromConfigFile();
0307: dataShareServer.initialize();
0308: }
0309: catch(Exception e)
0310: {
0311: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.GENERALSTATUS,
0312: "Problems in DataShareServer.main()...");
0313: loggingInterface.logException(LoggingInterface.ERROR, e);
0314: }
0315: try{
0316: // register the shutdown hook
0317: final DataShareServer dss = dataShareServer;
0318: Runtime.getRuntime().addShutdownHook(new Thread()
0319: {
0320: public void run()
0321: {
0322: System.out.println("shutdownHook()...");
0323: dss.shutDownConnectionsAndThreads();
0324: }
0325: });
0326: }
0327: catch(Exception e){}
0328: }
0329:
0330: /**
0331: * uses the *InterfaceClassName to try to load the classes and
0332: * make them available for general use
0333: */
0334: private void loadInterfaces() {
0335: // we will let InterfaceClassName values that are not set generate an exception
0336: // and disable their interfaces that way (cleaner than putting in test for strings)
0337:
0338: // logging interface (configuration may request we may replace the one we are using now)
0339: try {
0340: if (loggingInterfaceClassName != null
0341: && !loggingInterfaceClassName.equals("")) {
0342: final ClassLoader cl = getClass().getClassLoader();
0343: LoggingInterface li = (LoggingInterface) cl.loadClass(
0344: loggingInterfaceClassName).newInstance();
0345: loggingInterface.debugMsg(loggingInterface.DEBUG,
0346: loggingInterface.GENERALSTATUS,
0347: "LoggingInterface class loaded-> " + li);
0348: loggingInterface
0349: .debugMsg(loggingInterface.DEBUG,
0350: loggingInterface.GENERALSTATUS,
0351: "Logging will now be handled by the new class...");
0352: loggingInterface = li; // don't replace ours until it is loaded
0353: SessionUtilities.setLoggingInterface(li);
0354: loggingInterface.debugMsg(loggingInterface.DEBUG,
0355: loggingInterface.GENERALSTATUS,
0356: "Start of new LoggingInterface class");
0357: }
0358: } catch (Exception e) {
0359: loggingInterface.debugMsg(loggingInterface.WARNING,
0360: loggingInterface.GENERALSTATUS,
0361: "Problem when trying to load LoggingInterface class-> "
0362: + loggingInterfaceClassName + "\n" + e);
0363: }
0364:
0365: // persistence interface
0366: try {
0367: if (persistenceInterfaceClassName != null
0368: && !persistenceInterfaceClassName.equals("")) {
0369: final ClassLoader cl = getClass().getClassLoader();
0370: persistenceInterface = (PersistenceInterface) cl
0371: .loadClass(persistenceInterfaceClassName)
0372: .newInstance();
0373: loggingInterface.debugMsg(loggingInterface.DEBUG,
0374: loggingInterface.GENERALSTATUS,
0375: "PersistenceInterface class loaded-> "
0376: + persistenceInterface);
0377: persistenceAdapterFound = true;
0378: }
0379: } catch (Exception e) {
0380: loggingInterface.debugMsg(loggingInterface.WARNING,
0381: loggingInterface.GENERALSTATUS,
0382: "Problem when trying to load PersistenceInterface class-> "
0383: + persistenceInterfaceClassName + "\n" + e);
0384: //e.printStackTrace();
0385: persistenceAdapterFound = false;
0386: } finally {
0387: if (!persistenceAdapterFound) // otherwise, leave follow values as-is
0388: {
0389: useDatabase = false;
0390: persistData = false;
0391: authenticatingClients = false;
0392: }
0393: }
0394:
0395: // service interface
0396: try {
0397: if (serviceInterfaceClassName != null
0398: && !serviceInterfaceClassName.equals("")) {
0399: final ClassLoader cl = getClass().getClassLoader();
0400: serviceInterface = (ServiceInterface) cl.loadClass(
0401: serviceInterfaceClassName).newInstance();
0402: loggingInterface.debugMsg(loggingInterface.DEBUG,
0403: loggingInterface.GENERALSTATUS,
0404: "ServiceInterface class loaded-> "
0405: + serviceInterface);
0406: serviceAdapterFound = true;
0407: }
0408: } catch (Exception e) {
0409: loggingInterface.debugMsg(loggingInterface.WARNING,
0410: loggingInterface.GENERALSTATUS,
0411: "Problem when trying to load ServiceInterface class-> "
0412: + serviceInterfaceClassName + "\n" + e);
0413: //e.printStackTrace();
0414: serviceAdapterFound = false;
0415: } finally {
0416: if (!serviceAdapterFound) // otherwise, leave follow values as-is
0417: {
0418: // not sure what to disable
0419: }
0420: }
0421:
0422: // log in interface
0423: try {
0424: if (logInInterfaceClassName != null
0425: && !logInInterfaceClassName.equals("")) {
0426: final ClassLoader cl = getClass().getClassLoader();
0427: logInInterface = (LogInInterface) cl.loadClass(
0428: logInInterfaceClassName).newInstance();
0429: loggingInterface.debugMsg(loggingInterface.DEBUG,
0430: loggingInterface.GENERALSTATUS,
0431: "LogInInterface class loaded-> "
0432: + logInInterface);
0433: logInAdapterFound = true;
0434: } else
0435: authenticatingClients = false;
0436: } catch (Exception e) {
0437: loggingInterface.debugMsg(loggingInterface.DEBUG,
0438: loggingInterface.GENERALSTATUS,
0439: "Problem when trying to load LogInInterface class-> "
0440: + logInInterfaceClassName + "\n" + e);
0441: e.printStackTrace();
0442: logInAdapterFound = false;
0443: authenticatingClients = false;
0444: }
0445: }
0446:
0447: /**
0448: * give default values to properties
0449: */
0450: void initializeValues(String args[]) {
0451: // order for properties is default, file, system, (ads), commandLine)
0452: // Note that all these key values should have a attribute by the same name!!!!,
0453: // i.e. there is an attribute named 'persistenceInterfaceClassName' (that may be overwritten by the properties manager)
0454:
0455: // (note that ADS implementation will prepend "k2.datashare." to all these values in their configuration files)
0456: // The first value is the attribute names that we want to be initialized!!!
0457: // The second value is the type of the attribute (boolean, String, or int)
0458: // The third value is the default, may be overidden by PropertiesManager
0459: String propertiesStrings[][] = {
0460: { "persistenceInterfaceClassName", "String", "" },
0461: { "loggingInterfaceClassName", "String", "" }, // default value is in code, value here will override it
0462: { "logInInterfaceClassName", "String", "" },
0463: { "serviceInterfaceClassName", "String", "" },
0464: { "propertiesInterfaceClassName", "String", "" }, // default value is in code, value here will override it
0465: { "persistData", "boolean", "true" },
0466: { "useDatabase", "boolean", "true" },
0467: { "authenticatingClients", "boolean", "true" },
0468: { "firstPort", "int", "9000" },
0469: { "lastPort", "int", "10000" },
0470: { "debug", "boolean", "true" },
0471: { "commandStatusPort", "int", "42422" },
0472: { "multiCastIPaddress", "String", "228.6.6.6" },
0473: { "TCPSocketReadTimeout", "int", "0" }, // if non-zero, TCP sockets will timeout after this many milliseconds of inactivity and send KeepAlive packets
0474: { "showArchivedSessionsToAdmin", "boolean", "false" },
0475: {
0476: "serverVersion",
0477: "String",
0478: "DataShareServer\n"
0479: + "February 21, 2002\n"
0480: + "Version 1.09a\n"
0481: + "Copyright Ball Aerospace & Technologies Corp, 2002 Fairborn, Ohio" }, // symbol causes CVS import problems!!!
0482: {
0483: "serverVersionHtml",
0484: "String",
0485: "DataShareServer<br>"
0486: + "February 21, 2002<br>"
0487: + "Version 1.09a<br>"
0488: + "Copyright (c) Ball Aerospace & Technologies Corp, 2002<br>Fairborn, Ohio" }, // symbol causes CVS import problems!!!
0489: { "myClientKeyValue", "String", "DataShareServer" },
0490: { "propertiesFile", "String", "DataShare2.properties" }, // put additional properties here
0491: { "channelTypesFile", "String", "Rendezvous.cfg" } };
0492:
0493: // put the default values into our table
0494: for (int x = 0; x < propertiesStrings.length; x++)
0495: properties.put(propertiesStrings[x][0],
0496: propertiesStrings[x][2]);
0497:
0498: // try to get a PropertiesManager loaded and run...
0499:
0500: // properties manager is a unique problem because we want to be able to run different adapters,
0501: // and it is the class that would tell us about a different adapter... So we run it the first
0502: // time with the generic propertiesManagerAdapter, and if it returns with a non-default value for
0503: // the propertiesAdapter value, we will run the new class.
0504:
0505: // first we use the built in properties manager as our propertiesInterface
0506: propertiesInterface = new PropertiesManagerAdapter();
0507: propertiesInterface.setParameters(properties);
0508: propertiesInterface.setCommandLineArgs(args);
0509: properties = propertiesInterface.updateProperties();
0510:
0511: // now see if the propertiesInterface is to be replaced...
0512: String propertiesAdapterClassName = (String) properties
0513: .get("propertiesInterfaceClassName");
0514: if (propertiesAdapterClassName != null
0515: && !propertiesAdapterClassName.equals("")) {
0516: loggingInterface.debugMsg(loggingInterface.DEBUG,
0517: loggingInterface.GENERALSTATUS,
0518: "New PropertiesInterface class specified-> "
0519: + propertiesAdapterClassName);
0520: try {
0521: final ClassLoader cl = getClass().getClassLoader();
0522: propertiesInterface = (PropertiesInterface) cl
0523: .loadClass(propertiesAdapterClassName)
0524: .newInstance();
0525: loggingInterface.debugMsg(loggingInterface.DEBUG,
0526: loggingInterface.GENERALSTATUS,
0527: "New PropertiesInterface class loaded-> "
0528: + propertiesInterface);
0529: propertiesInterface.setParameters(properties);
0530: propertiesInterface.setCommandLineArgs(args);
0531: properties = propertiesInterface.updateProperties();
0532: } catch (Exception e) {
0533: loggingInterface.debugMsg(loggingInterface.WARNING,
0534: loggingInterface.GENERALSTATUS,
0535: "Problem when trying to load PropertiesInterface class ("
0536: + propertiesAdapterClassName + ")->\n"
0537: + e);
0538: //e.printStackTrace();
0539: }
0540: }
0541:
0542: // now we convert the (updated) properties values into attribute values...
0543: // wanted to use Class.getClass().getDeclaredField(fieldName), but it doesn't support Strings!
0544: for (int x = 0; x < propertiesStrings.length; x++) {
0545: String fieldName = propertiesStrings[x][0];
0546: String value = (String) properties.get(fieldName);
0547: loggingInterface.debugMsg(loggingInterface.DEBUG,
0548: loggingInterface.GENERALSTATUS, "Field/Value-> "
0549: + fieldName + "=" + value);
0550: try {
0551: Field field = this .getClass().getDeclaredField(
0552: fieldName);
0553: if (propertiesStrings[x][1].equals("int")) {
0554: int intValue = new Integer(value).intValue();
0555: field.setInt(this , intValue);
0556: } else if (propertiesStrings[x][1].equals("String")) {
0557: field.set(this , value);
0558: } else if (propertiesStrings[x][1].equals("boolean")) {
0559: // value must be "true" or "false" or value not used
0560: if (value.toLowerCase().equals("true"))
0561: field.setBoolean(this , true);
0562: else if (value.toLowerCase().equals("false"))
0563: field.setBoolean(this , false);
0564: }
0565: } catch (Exception e) {
0566: //e.printStackTrace();
0567: }
0568: }
0569: currentPort = firstPort; // this one value is based on another value (that may have just been changed)
0570:
0571: // must be a better way to do this, need to get a parameter to SessionUtilities' static values
0572: SessionUtilities.setTCPSocketReadTimeout(TCPSocketReadTimeout);
0573: }
0574:
0575: /**
0576: * Creates the CommandStatus Channel for communicating with Clients
0577: */
0578: public void initialize() {
0579: // create the descriptor for our CommandStatus Channel Connection
0580: commandStatusDescriptor = new DataShareConnectionDescriptor("",
0581: new ChannelDescription("commandStatus", "",
0582: "used to communicate with server",
0583: ChannelDescription.TCP, "dummy.jar", false,
0584: false, false, 0, 0), myIPAddress,
0585: commandStatusPort);
0586:
0587: try {
0588: if (!useDatabase) {
0589: // cannot persist data or authenticate clients without a database
0590: persistData = false;
0591: authenticatingClients = false; // we don't currently authenticate, but for later on...
0592: showArchivedSessionsToAdmin = false;
0593: }
0594:
0595: if (persistData) // already checked against useDatabase
0596: {
0597: loggingInterface.debugMsg(loggingInterface.DEBUG,
0598: loggingInterface.DATABASE,
0599: "We will be using a Database...");
0600: // create a Queue that will store then create our data for us
0601: persistDataQueue = new FifoQueue();
0602: persistDataQueue.setConsumer(this );
0603: } else {
0604: loggingInterface.debugMsg(loggingInterface.DEBUG,
0605: loggingInterface.DATABASE,
0606: "We will NOT be using a Database...");
0607: }
0608:
0609: // create the CommandStatus Channel socket listener thread
0610: commandStatusServerThread = new TcpSocketServer(
0611: (DataReceiverInterface) this , commandStatusPort,
0612: SessionUtilities.SocketRcvCmdPriority);
0613: treeView = new TreeView((TreeViewServerInterface) this );
0614: createSessions(treeView.oldSessionsTable);
0615: treeView = new TreeView((TreeViewServerInterface) this );
0616: // activate it so it will establish sockets for every connection
0617: commandStatusServerThread.start();
0618: serverInfoString = "<tr><td>Server version</td><td>"
0619: + serverVersionHtml + "</td></tr>"
0620: + "<tr><td>Server persistance</td><td>"
0621: + (persistData ? "Is " : "Is not ")
0622: + "saving data to a database" + "</td></tr>"
0623: + "<tr><td>Server up since</td><td>"
0624: + serverStartTime + "</td></tr>"
0625: + "<tr><td>Machine name</td><td> "
0626: + myIPAddress.getHostName() + "</td></tr>"
0627: + "<tr><td>Machine IP</td><td>"
0628: + myIPAddress.getHostAddress() + "</td></tr>"
0629: + "<tr><td>Command/Status port</td><td>"
0630: + commandStatusPort + "</td></tr>";
0631: } catch (Exception e) {
0632: loggingInterface.debugMsg(loggingInterface.ERROR,
0633: loggingInterface.GENERALSTATUS,
0634: "Not able to initialize DataShareServer");
0635: loggingInterface.logException(LoggingInterface.ERROR, e);
0636: this .shutDownConnectionsAndThreads();
0637: }
0638: }
0639:
0640: // what follows are event driven by network data on the CommandStatus Channel...
0641:
0642: static int objectCount = 0; // used to count each object received from a client over the commandStatusConnection
0643:
0644: /**
0645: * All DataShare connections require that the user 'register' on the channel before it
0646: * will be made 'active' by the server. this is so the server can associate a unique client
0647: * name with each socket. The client must register with the server before it will
0648: * be added as a Client that other Clients can see. The data received here is from the
0649: * clients commandStatusConnection channel. Note that when we call ts.sendData() here,
0650: * the object sent goes to client the message was received from only. Also note that
0651: * calls to this method come from the Thread of the Socket from which the data was received.
0652: */
0653: public/* synchronized */void clientDataReceived(
0654: DataShareObject dsObject, SocketAdapter ts) {
0655: objectCount++;
0656: try {
0657: Object object = SessionUtilities
0658: .retrieveObject(dsObject.objectBytes);
0659:
0660: if (object instanceof RegistrationInfo) {
0661: RegistrationInfo ri = (RegistrationInfo) object;
0662: loggingInterface.debugMsg(loggingInterface.DEBUG,
0663: loggingInterface.CLIENT,
0664: "Received RegistrationInfo object from "
0665: + ri.clientUserName);
0666: // put client into client table and clientmachines table and create ServerInfo that has clients unique name
0667: ServerInfo si = addClient(ri, ts);
0668: loggingInterface.debugMsg(loggingInterface.DEBUG,
0669: loggingInterface.CLIENT,
0670: "Sending ServerInfo to "
0671: + (si.clientRegistered ? ts
0672: .getClientKey()
0673: : ri.clientUserName));
0674: ts.sendData(new DataShareObject(SessionUtilities
0675: .convertObjectToByteArray(si), ts.getType(),
0676: myClientKeyValue));
0677: loggingInterface.debugMsg(loggingInterface.DEBUG,
0678: loggingInterface.GENERALSTATUS,
0679: "Free Memory - "
0680: + Runtime.getRuntime().freeMemory()
0681: / 1024 + " (Kbytes)");
0682: loggingInterface.debugMsg(loggingInterface.DEBUG,
0683: loggingInterface.GENERALSTATUS,
0684: "Used Memory - "
0685: + Runtime.getRuntime().totalMemory()
0686: / 1024 + " (Kbytes)");
0687: } else if (object instanceof RequestFunctionInfo) {
0688: // send new client a list of possible Channel types
0689: loggingInterface.debugMsg(loggingInterface.DEBUG,
0690: loggingInterface.CLIENT,
0691: "Sending ChannelDescriptionArray to "
0692: + ts.getClientKey());
0693: ts
0694: .sendData(new DataShareObject(
0695: SessionUtilities
0696: .convertObjectToByteArray(channelDescriptionArray),
0697: ts.getType(), myClientKeyValue));
0698: } else if (object instanceof CreateSessionRequest) {
0699: CreateSessionRequest csr = (CreateSessionRequest) object;
0700: loggingInterface.debugMsg(loggingInterface.DEBUG,
0701: loggingInterface.CLIENT,
0702: "Received CreateSessionRequest object from "
0703: + ts.getClientKey());
0704: // create the session, and all its channels, taking care to do all the recording
0705: ClientSessionInfo csi = createSession(ts, csr);
0706: // send info to requesting client so it will join the session
0707: if (csi != null) {
0708: loggingInterface.debugMsg(loggingInterface.DEBUG,
0709: loggingInterface.CLIENT,
0710: "Sending ClientSessionInfo to "
0711: + ts.getClientKey());
0712: ts.sendData(new DataShareObject(SessionUtilities
0713: .convertObjectToByteArray(csi), ts
0714: .getType(), myClientKeyValue));
0715: // // add an inactive consumer to every channel that client will try to join
0716: // for(int x=0; x<csi.dsConnDescriptor.length; x++)
0717: // {
0718: // this.addConsumer(ts.getClientKey(), csi.sessionName, csi.dsConnDescriptor[x].channelDescription.channelName,false);
0719: // }
0720: }
0721: } else if (object instanceof JoinSession) {
0722: // any client that sends us a JoinSession object will be sent the corresponding ClientSessionInfo object
0723: JoinSession sessionToJoin = (JoinSession) object;
0724: loggingInterface.debugMsg(loggingInterface.DEBUG,
0725: loggingInterface.CLIENT,
0726: "Received JoinSession object from "
0727: + ts.getClientKey());
0728: // find the session
0729: if (sessionTable
0730: .containsKey(sessionToJoin.sessionKeyValue)) {
0731: loggingInterface.debugMsg(loggingInterface.DEBUG,
0732: loggingInterface.CLIENT,
0733: "Found JoinSession Session "
0734: + sessionToJoin.sessionKeyValue);
0735: SessionInfo sessionInfo = (SessionInfo) sessionTable
0736: .get(sessionToJoin.sessionKeyValue);
0737: ClientSessionInfo csi = new ClientSessionInfo(
0738: sessionInfo.getName(), sessionInfo
0739: .getSessionDescription(),
0740: sessionInfo.getKeyValue(), sessionInfo
0741: .getChannelConnectionDescriptors(),
0742: false, false); // not new session, not private
0743: // send info to requesting client so it will join the session
0744: if (csi != null) {
0745: loggingInterface.debugMsg(
0746: loggingInterface.DEBUG,
0747: loggingInterface.CLIENT,
0748: "Sending ClientSessionInfo to "
0749: + ts.getClientKey());
0750: ts.sendData(new DataShareObject(
0751: SessionUtilities
0752: .convertObjectToByteArray(csi),
0753: ts.getType(), myClientKeyValue));
0754: // // add an inactive consumer to every channel that client will try to join
0755: // for(int x=0; x<csi.dsConnDescriptor.length; x++)
0756: // {
0757: // this.addConsumer(ts.getClientKey(), csi.sessionName, csi.dsConnDescriptor[x].channelDescription.channelName,false);
0758: // }
0759: }
0760: } else {
0761: loggingInterface.debugMsg(loggingInterface.DEBUG,
0762: loggingInterface.CLIENT,
0763: "Client requested to join a session that could not be found->\nClient: "
0764: + ts.getClientKey() + " Session: "
0765: + sessionToJoin.sessionKeyValue);
0766: }
0767: } else if (object instanceof RequestSessionNames) {
0768: RequestSessionNames rsn = (RequestSessionNames) object;
0769: Vector vec = new Vector();
0770: for (Enumeration e = sessionTable.elements(); e
0771: .hasMoreElements();) {
0772: SessionInfo this SessionInfo = (SessionInfo) e
0773: .nextElement();
0774: if (ts.getClientClass().equals(
0775: this SessionInfo.getClientClass())) // session class same as requested class?
0776: vec.add(this SessionInfo.getName());
0777: }
0778: String[] retValue = new String[vec.size()];
0779: for (int x = 0; x < retValue.length; x++)
0780: retValue[x] = (String) vec.elementAt(x);
0781: SessionNames sn = new SessionNames(retValue);
0782: ts.sendData(new DataShareObject(SessionUtilities
0783: .convertObjectToByteArray(sn), ts.getType(),
0784: myClientKeyValue));
0785: } else if (object instanceof RequestFunctionsInSession) {
0786: RequestFunctionsInSession rfis = (RequestFunctionsInSession) object;
0787: FunctionsInSession fis = new FunctionsInSession(
0788: rfis.sessionName);
0789: if (sessionTable.containsKey(rfis.sessionName)) {
0790: Vector vec = new Vector();
0791: SessionInfo si = (SessionInfo) sessionTable
0792: .get(rfis.sessionName);
0793: for (Enumeration e = si.getChannelTable()
0794: .elements(); e.hasMoreElements();) {
0795: ChannelInfo ci = (ChannelInfo) e.nextElement();
0796: String functionName = ci
0797: .getConnectionDescriptor().channelDescription.channelName;
0798: vec.add(functionName);
0799: }
0800: String[] retValue = new String[vec.size()];
0801: for (int x = 0; x < retValue.length; x++)
0802: retValue[x] = (String) vec.elementAt(x);
0803: fis.setFunctionsInSession(retValue);
0804: }
0805: ts.sendData(new DataShareObject(SessionUtilities
0806: .convertObjectToByteArray(fis), ts.getType(),
0807: myClientKeyValue));
0808: } else if (object instanceof RequestTree) {
0809: loggingInterface.debugMsg(loggingInterface.DEBUG,
0810: loggingInterface.CLIENT,
0811: "Received RequestTree object from "
0812: + ts.getClientKey());
0813: // let treeView create a tree customized for this Client
0814: TreeObject tree = new TreeObject(treeView
0815: .getExternalTreeNode(this .getClientInfo(ts
0816: .getClientKey())));
0817: // if we are showing archived sessions, and this client is admin, add archived sessions to tree
0818: if (showArchivedSessionsToAdmin && ts.getAdmin())
0819: tree.allNodes.add(treeView
0820: .getExternalArchivedNode());
0821: // send the tree!
0822: ts.sendData(new DataShareObject(SessionUtilities
0823: .convertObjectToByteArray(tree), ts.getType(),
0824: myClientKeyValue));
0825: } else if (object instanceof RegisterTreeListener) {
0826: loggingInterface.debugMsg(loggingInterface.DEBUG,
0827: loggingInterface.CLIENT,
0828: "Received RegisterTreeListener object from "
0829: + ts.getClientKey());
0830: RegisterTreeListener rtl = (RegisterTreeListener) object;
0831: // set ClientInfo to reflect what type of clients this client will see in its tree
0832: ClientInfo clientInfo = this .getClientInfo(ts
0833: .getClientKey());
0834: clientInfo.setSeeAllTreeObjects(rtl.allChanges);
0835: treeView.addTreeListener(clientInfo, ts);
0836: } else if (object instanceof DeleteSession) {
0837: loggingInterface.debugMsg(loggingInterface.DEBUG,
0838: loggingInterface.CLIENT,
0839: "Received DeleteSession object from "
0840: + ts.getClientKey());
0841: DeleteSession ds = (DeleteSession) object;
0842: deleteSession(ts, ds);
0843: } else if (object instanceof RequestHistory) {
0844: // we assume that clients do not ask for history if the server is not using beans
0845: loggingInterface.debugMsg(loggingInterface.DEBUG,
0846: loggingInterface.CLIENT,
0847: "Received RequestHistory object from "
0848: + ts.getClientKey());
0849: RequestHistory rh = (RequestHistory) object;
0850: if (rh.typeOfRequest == RequestHistory.COUNT) {
0851: int numberOfBeans = 0;
0852: HistoryCountObject ho = null;
0853: // put consumer in tree with active=false before we get the count...
0854: this .addConsumer(ts.getClientKey(), rh.sessionName,
0855: rh.channelName, false);
0856: // use the provided ADSKey for the Channel to get the beans...
0857: // this is a blocking call, but we don't care because it is in the thread for the client commandStatusSocket
0858: numberOfBeans = RetreiveDataBeans
0859: .getDataCount(persistenceInterface,
0860: rh.channelDatabaseKey);
0861: ho = new HistoryCountObject(rh.sessionName,
0862: rh.channelDatabaseKey, numberOfBeans);
0863: loggingInterface.debugMsg(loggingInterface.DEBUG,
0864: loggingInterface.CLIENT,
0865: "Sending HistoryCountObject for channel "
0866: + rh.channelDatabaseKey
0867: + ", objects found: "
0868: + numberOfBeans);
0869: ts.sendData(new DataShareObject(SessionUtilities
0870: .convertObjectToByteArray(ho),
0871: ts.getType(), myClientKeyValue));
0872: } else if (rh.typeOfRequest == RequestHistory.DATA
0873: || rh.typeOfRequest == RequestHistory.CANCEL) {
0874: loggingInterface
0875: .debugMsg(
0876: loggingInterface.ERROR,
0877: loggingInterface.CLIENT,
0878: "*** received RequestHistory for Data/Cancel in commandStatus channel, should be in Data Channel!!");
0879: }
0880: } else if (object instanceof DisconnectConsumer) {
0881: loggingInterface.debugMsg(loggingInterface.DEBUG,
0882: loggingInterface.CLIENT,
0883: "Received DisconnectConsumer object from "
0884: + ts.getClientKey());
0885: DisconnectConsumer dc = (DisconnectConsumer) object;
0886: if (ts.getClientKey().equals(dc.clientKey)) // can only remove yourself
0887: {
0888: this .removeAndDisconnectConsumer(dc.clientKey,
0889: dc.sessionKey, dc.channelKey);
0890: } else {
0891: loggingInterface.debugMsg(loggingInterface.ERROR,
0892: loggingInterface.CLIENT,
0893: "DisconnectConsumer incorrect client!! "
0894: + ts.getClientKey()
0895: + " disconnecting " + dc.clientKey);
0896: }
0897: } else if (object instanceof TokenRequestObject) {
0898: loggingInterface.debugMsg(loggingInterface.DEBUG,
0899: loggingInterface.CLIENT,
0900: "Received TokenRequestObject from "
0901: + ts.getClientKey());
0902: TokenRequestObject tro = (TokenRequestObject) object;
0903: tokenRequestReceived(tro, ts);
0904: } else if (object instanceof InstantMsgData) {
0905: // forward this IM
0906: loggingInterface.debugMsg(loggingInterface.DEBUG,
0907: loggingInterface.CLIENT,
0908: "Received InstantMsg object from "
0909: + ts.getClientKey());
0910: InstantMsgData imd = (InstantMsgData) object;
0911:
0912: // loop for each client this message goes to
0913: for (int x = 0; x < imd.destinationClientKeyValue.length; x++) {
0914: // send data to one socket at a time...
0915: SocketAdapter tsDestinationClient = (SocketAdapter) commandStatusSocketHandlers
0916: .get(imd.destinationClientKeyValue[x]);
0917: if (tsDestinationClient != null) {
0918: tsDestinationClient.sendData(dsObject); // send same object
0919: loggingInterface
0920: .debugMsg(
0921: loggingInterface.DEBUG,
0922: loggingInterface.CLIENT,
0923: "Sent an IM to "
0924: + imd.destinationClientKeyValue[x]);
0925: } else {
0926: loggingInterface
0927: .debugMsg(
0928: loggingInterface.WARNING,
0929: loggingInterface.CLIENT,
0930: "Could not find this client to send the IM to-> "
0931: + imd.destinationClientKeyValue[x]);
0932: }
0933: }
0934: } else if (object instanceof ControlServerObject) {
0935: loggingInterface.debugMsg(loggingInterface.DEBUG,
0936: loggingInterface.GENERALSTATUS,
0937: "Received ControlServerObject from "
0938: + ts.getClientKey());
0939: ControlServerObject cso = (ControlServerObject) object;
0940: if (cso.serviceType == ControlServerObject.VERBOSEserviceType) {
0941: if (cso.serviceValueInt == ControlServerObject.ONserviceValue) {
0942: loggingInterface
0943: .debugMsg(
0944: loggingInterface.DEBUG,
0945: loggingInterface.GENERALSTATUS,
0946: "Admin Client "
0947: + ts.getClientKey()
0948: + " has requested that Verbose be turned on");
0949: debug = true;
0950: } else if (cso.serviceValueInt == ControlServerObject.OFFserviceValue) {
0951: loggingInterface
0952: .debugMsg(
0953: loggingInterface.DEBUG,
0954: loggingInterface.GENERALSTATUS,
0955: "Admin Client "
0956: + ts.getClientKey()
0957: + " has requested that Verbose be turned off");
0958: debug = false;
0959: }
0960: }
0961: SessionUtilities.setVerbose(debug);
0962: ServerStatusObject sso = new ServerStatusObject(debug);
0963: // so all clients get it, not just the one that sent this object
0964: sendToAllCommandStatusClients(sso);
0965: } else {
0966: String objectClass = "unknown";
0967: try {
0968: objectClass = object.getClass().toString();
0969: } catch (Exception e) {
0970: }
0971: loggingInterface
0972: .debugMsg(loggingInterface.WARNING,
0973: loggingInterface.GENERALSTATUS,
0974: "unknown object type received-> "
0975: + objectClass);
0976: }
0977: } catch (Exception e) {
0978: loggingInterface.debugMsg(loggingInterface.ERROR,
0979: loggingInterface.CLIENT,
0980: "Problems with received data from client ("
0981: + ts.getClientKey() + ")");
0982: loggingInterface.logException(LoggingInterface.ERROR, e);
0983: //e.printStackTrace();
0984: }
0985: }
0986:
0987: /**
0988: * this will take a hashtable of SessionInfo objects (which contain ChannelInfo objects), and try
0989: * to create the Sessions/Channels specified.
0990: */
0991: private void createSessions(Hashtable sessions) {
0992: for (Enumeration enumS = sessions.elements(); enumS
0993: .hasMoreElements();) {
0994: try {
0995: SessionInfo si = (SessionInfo) enumS.nextElement();
0996: System.out.println("Re-opening Session named -> "
0997: + si.getName());
0998: sessionTable.put(si.getKeyValue(), si);
0999: // tell clients about new session...
1000: treeView.addSession(si);
1001:
1002: for (Enumeration enumC = si.getChannelTable()
1003: .elements(); enumC.hasMoreElements();) {
1004: ChannelInfo ci = (ChannelInfo) enumC.nextElement();
1005: // make sure we still have a Channel of that type...
1006: boolean found = false;
1007: for (int x = 0; x < channelDescriptionArray.channelDescriptions.length; x++) {
1008: // channelName must match
1009: if (channelDescriptionArray.channelDescriptions[x].channelName
1010: .equals(ci.getConnectionDescriptor().channelDescription.channelName))
1011: if (channelDescriptionArray.channelDescriptions[x].type == ci
1012: .getConnectionDescriptor().channelDescription.type)
1013: if (channelDescriptionArray.channelDescriptions[x].channelClass
1014: .equals(ci
1015: .getConnectionDescriptor().channelDescription.channelClass)) {
1016: found = true;
1017: System.out
1018: .println("Re-opening Session with channel named -> "
1019: + ci
1020: .getConnectionDescriptor().channelDescription.channelName);
1021: }
1022: }
1023: if (found) // then we can create this channel
1024: {
1025: ChannelInfo this Channel = createChannel(
1026: ci.getConnectionDescriptor().channelDescription,
1027: si, false); // false so we don't create si/ci EJB again
1028:
1029: this Channel.setSaveDataForThisChannel(ci
1030: .getSaveDataForThisChannel()
1031: && this .persistData);
1032: if (this Channel.getSaveDataForThisChannel()) {
1033: String key = ci.getDatabaseID();
1034: System.out
1035: .println("Re-opening saved Session found Channel database ID of "
1036: + key);
1037: this Channel.setDatabaseID(key);
1038: this Channel.getConnectionDescriptor().databaseID = key;
1039: this Channel.getDataReceiverAdapter()
1040: .setChannelInfo(this Channel);
1041: this Channel.getDataReceiverAdapter()
1042: .setChannelDatabaseKey(key);
1043: this Channel.getDataReceiverAdapter().sequence = RetreiveDataBeans
1044: .getDataCount(persistenceInterface,
1045: key);
1046: } else
1047: System.out
1048: .println("Re-opening saved Session found Channel that is not saving data -> "
1049: + ci.getName());
1050:
1051: ChannelInfo removedChannelInfo = (ChannelInfo) si
1052: .getChannelTable().remove(
1053: ci.getKeyValue());
1054: if (removedChannelInfo == null)
1055: System.out
1056: .println("OH NO!!! Did not remove channel ("
1057: + ci.getKeyValue()
1058: + ") from re-opened Session!!!");
1059: si.addChannel(this Channel); // save new one that may have new ports, etc.
1060: treeView.addChannel(this Channel);
1061: } else
1062: System.out
1063: .println("Re-opening saved Session could not find ChannelDescription -> "
1064: + " name="
1065: + ci.getConnectionDescriptor().channelDescription.channelName
1066: + ",type="
1067: + ChannelDescription.validTypes[ci
1068: .getConnectionDescriptor().channelDescription.type]
1069: + ",class="
1070: + ci.getConnectionDescriptor().channelDescription.channelClass);
1071:
1072: }
1073: } catch (Exception e) {
1074: /***/
1075: e.printStackTrace(); // need to change to new logging methods
1076: }
1077: }
1078: System.out.println("Re-opening Sessions completed");
1079: }
1080:
1081: /**
1082: * this is used when it is necessary to send an object to all clients over their
1083: * commandStatusConnection.
1084: */
1085: private void
1086: sendToAllCommandStatusClients(Object object)
1087: {
1088: for(Enumeration enum = this .commandStatusSocketHandlers.elements(); enum.hasMoreElements();)
1089: {
1090: SocketAdapter sa = null;
1091: try{
1092: sa = (SocketAdapter)enum.nextElement();
1093: sa.sendData((new DataShareObject(SessionUtilities.convertObjectToByteArray(object), sa.getType(), myClientKeyValue)));
1094: }
1095: catch(Exception e)
1096: {
1097: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.CLIENT,
1098: "Problem sending data to client ("+ (sa==null?null:sa.getClientKey()) +")");
1099: loggingInterface.logException(LoggingInterface.ERROR, e);
1100: }
1101: }
1102: }
1103:
1104: /**
1105: * Processes the object from a client that is requesting Session be deleted from the
1106: * Server. The Session must have no clients, and the requester must be the owner, or
1107: * an admin client. A check will also be made to see if the data was persisted and
1108: * the methods to archive it are provided in it's ChannelData information.
1109: */
1110: private void deleteSession(SocketAdapter ts, DeleteSession ds) {
1111: boolean sessionIsInArchives = false;
1112: // is requestor owner or admin?
1113: SessionInfo si = (SessionInfo) sessionTable
1114: .get(ds.sessionKeyValue);
1115: if (si == null) {
1116: loggingInterface.debugMsg(loggingInterface.WARNING,
1117: loggingInterface.SESSION, "did not find session ("
1118: + ds.sessionKeyValue
1119: + ") to delete in active table...");
1120: // if session is from archives, sessionKeyValue will be ADSKey string instead of sessionName...
1121: si = (SessionInfo) treeView.oldSessionsTable
1122: .get(ds.sessionKeyValue);
1123: if (si != null) {
1124: sessionIsInArchives = true;
1125: loggingInterface.debugMsg(loggingInterface.DEBUG,
1126: loggingInterface.SESSION, "found session ("
1127: + ds.sessionKeyValue
1128: + ") to delete in the archives");
1129: }
1130: }
1131: ClientInfo ci = (ClientInfo) specialClientTable.get(ts
1132: .getClientKey().toLowerCase());
1133: if (si != null && ci != null) {
1134: loggingInterface.debugMsg(loggingInterface.DEBUG,
1135: loggingInterface.SESSION, "Client "
1136: + ts.getClientKey()
1137: + " is requesting Session " + si.getName()
1138: + " be deleted");
1139: // make sure session owner is client, or client is admin
1140: if (si.getOwnerName().equals(ci.getName()) || ci.getAdmin()) {
1141: // first, check that we are not being spoofed...
1142: SocketAdapter registeredSocketData = (SocketAdapter) commandStatusSocketHandlers
1143: .get(ts.getClientKey());
1144: if (ts.getRemoteIP() != registeredSocketData
1145: .getRemoteIP()) {
1146: // ignore data from Client whose IP address has 'changed' since registration
1147: loggingInterface.debugMsg(loggingInterface.WARNING,
1148: loggingInterface.GENERALSTATUS,
1149: "+++Someone is spoofing us:"
1150: + ts.getRemoteIP().toString()
1151: + " says they are "
1152: + registeredSocketData
1153: .getRemoteIP().toString());
1154: } else {
1155: boolean empty = true;
1156: // ensure there are no clients in the channel
1157: for (Enumeration channelEnum = si.getChannelTable()
1158: .elements(); channelEnum.hasMoreElements();) {
1159: ChannelInfo chan = (ChannelInfo) channelEnum
1160: .nextElement();
1161: Hashtable consumers = chan.getConsumerTable();
1162: if (consumers != null && !consumers.isEmpty()) {
1163: empty = false;
1164: break;
1165: }
1166: }
1167: if (empty) // proceed only if all Channels in this Session have no Consumers...
1168: {
1169: if (!sessionIsInArchives) {
1170: // remove Session from our tree, notify all clients, shutdown all Channel Sockets...
1171: loggingInterface
1172: .debugMsg(loggingInterface.DEBUG,
1173: loggingInterface.SESSION,
1174: "Delete Session found active session, testing for archivability...");
1175: treeView.removeSession(si);
1176: si.setActive(false);
1177: sessionTable.remove(ds.sessionKeyValue);
1178:
1179: //// need special test for BroadCastClient Session removal because it exists outside
1180: //// of sessionTable too...
1181: //if(ds.sessionKeyValue.equals(broadCastClientSessionName))
1182: // this.broadCastSessionInfo = null;
1183:
1184: for (Enumeration channelEnum = si
1185: .getChannelTable().elements(); channelEnum
1186: .hasMoreElements();) {
1187: ChannelInfo chan = (ChannelInfo) channelEnum
1188: .nextElement();
1189: chan.setActive(false);
1190: chan.shutDown();
1191: loggingInterface
1192: .debugMsg(
1193: loggingInterface.DEBUG,
1194: loggingInterface.SESSION,
1195: "Delete Session found channel {"
1196: + chan
1197: .getName()
1198: + "}, testing for archivability...");
1199: // decide if data from the Channel should be archived to DocumentKonnect...
1200: if (si.saveData
1201: && chan
1202: .getSaveDataForThisChannel()) // was data archived?
1203: {
1204: loggingInterface
1205: .debugMsg(
1206: loggingInterface.DEBUG,
1207: loggingInterface.SESSION,
1208: "Archivable data should be found for channel {"
1209: + chan
1210: .getName()
1211: + "}, testing for archive classes");
1212: ChannelDescription cd = chan
1213: .getConnectionDescriptor().channelDescription;
1214: if (cd.archiveChannelClass != null
1215: && !cd.archiveChannelClass
1216: .equals("")) // does the function in this Channel support archiving?
1217: {
1218: try {
1219: // String ownerKey = ci.getUserProxy().getID();
1220: archiveData(si, chan, si
1221: .getOwnerName()); // check to see if data should be saved to DK
1222: } catch (Exception e) {
1223: loggingInterface
1224: .debugMsg(
1225: loggingInterface.ERROR,
1226: loggingInterface.SESSION,
1227: "Problem in archiveData for class "
1228: + cd.archiveChannelClass);
1229: loggingInterface
1230: .logException(
1231: LoggingInterface.ERROR,
1232: e);
1233: }
1234: } else {
1235: loggingInterface
1236: .debugMsg(
1237: loggingInterface.DEBUG,
1238: loggingInterface.SESSION,
1239: "Archivable data for channel {"
1240: + chan
1241: .getName()
1242: + "} could not find archive classes");
1243: }
1244: } else {
1245: loggingInterface
1246: .debugMsg(
1247: loggingInterface.DEBUG,
1248: loggingInterface.SESSION,
1249: "Channel "
1250: + chan
1251: .getName()
1252: + " not able to archive");
1253: }
1254: } // end of for loop, looping on channels
1255: loggingInterface
1256: .debugMsg(loggingInterface.DEBUG,
1257: loggingInterface.SESSION,
1258: "Delete Session has processed all Channels for archivable data");
1259: if (si.saveData)
1260: deleteSessionData(si.getDatabaseID());
1261: } else // session is in archives
1262: {
1263: // now remove all references to this Session from the database
1264: deleteSessionData(si.getDatabaseID());
1265: }
1266: } else {
1267: // Session is not empty
1268: loggingInterface
1269: .debugMsg(loggingInterface.DEBUG,
1270: loggingInterface.SESSION,
1271: "deleteSession called for Session that still has at least one Consumer");
1272: }
1273: }
1274: } else {
1275: // session owner is not client, or client is not admin
1276: loggingInterface
1277: .debugMsg(loggingInterface.WARNING,
1278: loggingInterface.SESSION,
1279: "deleteSession was called by client that is not owner and not admin.");
1280: }
1281: } else {
1282: // cannot find Session or Channel
1283: loggingInterface
1284: .debugMsg(
1285: loggingInterface.WARNING,
1286: loggingInterface.SESSION,
1287: "deleteSession could not find Session ("
1288: + (si == null ? null : si.getName())
1289: + ") and/or requesting Client ("
1290: + ci == null ? null : ci
1291: .getKeyValue()
1292: + ")");
1293: }
1294: }
1295:
1296: /**
1297: * gets the archived data for this Channel, puts it back through its Function, takes output
1298: * byte[] and archives it into DK. It already should have been determined that this channel should
1299: * be archived and it supports archiving.
1300: */
1301: private void archiveData(SessionInfo si, ChannelInfo ci,
1302: String ownerKey) {
1303: loggingInterface.debugMsg(loggingInterface.DEBUG,
1304: loggingInterface.SESSION,
1305: "archiveData() called for Session/Channel: "
1306: + si.getName() + "/" + ci.getName());
1307: try {
1308: final ChannelDescription cd = ci.getConnectionDescriptor().channelDescription;
1309: Object archiveClass = null; // the class from the Function we will use to generate the byte[] to archive
1310:
1311: // find the class files for Channel function
1312: // first look locally
1313: try {
1314: final ClassLoader cl = this .getClass().getClassLoader();
1315: archiveClass = cl.loadClass(cd.archiveChannelClass)
1316: .newInstance();
1317: loggingInterface.debugMsg(loggingInterface.DEBUG,
1318: loggingInterface.SESSION, cd.channelName
1319: + "'s archive class loaded");
1320: } catch (Exception e) {
1321: loggingInterface.debugMsg(loggingInterface.ERROR,
1322: loggingInterface.SESSION, "Problem-> "
1323: + e.getMessage()
1324: + " when trying to load archive class");
1325: }
1326:
1327: if (archiveClass != null) // then we have our class loaded, find the method we need to put data into it...
1328: {
1329: final SessionInfo si2 = si;
1330: final ChannelInfo ci2 = ci;
1331: final String ownerKey2 = ownerKey;
1332: final Object archiveClass2 = archiveClass;
1333: // run the archiving from its own thread so we don't tie up the server's connection to this client
1334: final Runnable archiveTheData = new Runnable() {
1335: public void run() {
1336: Thread.currentThread().setName(
1337: "ArchiveTheDataThread");
1338: archiveDataLoop(si2, ci2, cd, ownerKey2,
1339: archiveClass2);
1340: }
1341: };
1342: Thread shortLivedThread = new Thread(archiveTheData);
1343: shortLivedThread.start();
1344: Thread.currentThread().yield();
1345: }
1346: } catch (Exception e) {
1347: loggingInterface.debugMsg(loggingInterface.ERROR,
1348: loggingInterface.SESSION,
1349: "Problem in archiveData()...");
1350: loggingInterface.logException(loggingInterface.ERROR, e);
1351: }
1352: }
1353:
1354: /**
1355: * this method should only be called by the above method, and the only reason this is
1356: * a method at all is because it needed to be run in a Thread of its own.
1357: */
1358: private void archiveDataLoop(SessionInfo si, ChannelInfo ci,
1359: ChannelDescription cd, String ownerKey, Object archiveClass) {
1360: try {
1361: RetreiveDataBeans retreiveDataBeans = new RetreiveDataBeans();
1362: Class[] parameter = { new DataShareObject().getClass() };
1363: Method setDataMethod = archiveClass.getClass().getMethod(
1364: cd.archiveChannelSetDataMethod, parameter);
1365: // loop on this method for all of the DataShareObjects that exists in our persisted data...
1366: int count = RetreiveDataBeans.getDataCount(
1367: persistenceInterface, ci.getDatabaseID());
1368: // get all the data
1369: retreiveDataBeans.retrieveAllData(persistenceInterface, ci
1370: .getDatabaseID()); // could take a while
1371: DataShareObject[] dsArray = retreiveDataBeans
1372: .getNextData(count);
1373: if (dsArray != null) {
1374: for (int x = 0; x < dsArray.length; x++) {
1375: Object[] dsParameter = { (Object) dsArray[x] };
1376: setDataMethod.invoke(archiveClass, dsParameter);
1377: }
1378: Method getDataMethod = archiveClass
1379: .getClass()
1380: .getMethod(cd.archiveChannelGetDataMethod, null); // no parameter
1381: byte[] fileData = (byte[]) getDataMethod.invoke(
1382: archiveClass, null);
1383:
1384: persistenceInterface
1385: .saveFunctionDataToDisk(ownerKey, si, ci,
1386: cd.fileExtension, fileData, cd.mimeType);
1387: loggingInterface
1388: .debugMsg(loggingInterface.DEBUG,
1389: loggingInterface.SESSION,
1390: "!!!!Successfully save this Functions data into DK!!!!!");
1391: } else {
1392: loggingInterface
1393: .debugMsg(loggingInterface.DEBUG,
1394: loggingInterface.SESSION,
1395: "There was no data to archive for this Channel");
1396: }
1397: } catch (Exception e) {
1398: loggingInterface.debugMsg(loggingInterface.ERROR,
1399: loggingInterface.SESSION,
1400: "Problem in archiveDataLoop...");
1401: loggingInterface.logException(LoggingInterface.ERROR, e);
1402: }
1403: }
1404:
1405: boolean dataLoopFinished;
1406:
1407: /**
1408: * this method will attempt to delete (remove from the database) all the data associated
1409: * with a Session. The databaseID String for the Session is all that is needed, and because
1410: * it can take a while to find and remove all the data, a new Thread is spawned to actually
1411: * do the task. This method should not be called if the server is not using beans.
1412: */
1413: private synchronized void deleteSessionData(String sessionDatabaseID) {
1414: if (this .getPersistData()) {
1415: loggingInterface.debugMsg(loggingInterface.DEBUG,
1416: loggingInterface.SESSION,
1417: "deleting data for Session " + sessionDatabaseID);
1418: final String sessionDatabaseID2 = sessionDatabaseID;
1419: // run the archiving from its own thread so we don't tie up the server's connection to this client
1420: final Runnable deleteTheData = new Runnable() {
1421: public void run() {
1422: Thread.currentThread().setName(
1423: "deleteTheDataThread");
1424: deleteSessionDataLoop(sessionDatabaseID2);
1425: }
1426: };
1427: Thread shortLivedThread = new Thread(deleteTheData);
1428: dataLoopFinished = false;
1429: shortLivedThread.start();
1430: if (treeView.oldSessionsTable
1431: .containsKey(sessionDatabaseID))
1432: treeView.oldSessionsTable.remove(sessionDatabaseID);
1433: Thread.currentThread().yield();
1434: // don't return until finished, we can exit DataShare before thread finished otherwise
1435: while (!dataLoopFinished)
1436: SessionUtilities.delay(200);
1437: }
1438: }
1439:
1440: /**
1441: * this method should only be called from the above method, the only reason this is a method
1442: * is so that it may be called from its own thread.
1443: */
1444: private void
1445: deleteSessionDataLoop(String sessionDatabaseID)
1446: {
1447: try{
1448: //ADSKey key = new ADSKey(sessionDatabaseID);
1449: //Enumeration enum = EjbUtil.findByQuery("DSSessionHome", "getID()='"+key+"'" );
1450: Enumeration enum = persistenceInterface.searchForUserObjects("DSSession3Home","getID()='"+sessionDatabaseID+"'");
1451: SessionInfo sessionInfo = (SessionInfo)enum.nextElement(); // should only be one session returned
1452: try{
1453: Enumeration enum2 = persistenceInterface.searchForUserObjects("DSChannel3Home", "getSessionKey()='"+sessionDatabaseID+"'" );
1454: // loop on all channels
1455: for( ; enum2.hasMoreElements(); )
1456: {
1457: try{
1458: ChannelInfo channelInfo = (ChannelInfo)enum2.nextElement();
1459: persistenceInterface.delete("DSData3Home", "getChannelKey()='"+channelInfo.getDatabaseID()+"'");
1460: persistenceInterface.delete("DSChannel3Home", "getID()='"+channelInfo.getDatabaseID()+"'");
1461: }
1462: catch(Exception e2)
1463: {
1464: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.DATABASE,
1465: "Problem with a channel in deleteSessionDataLoop...");
1466: loggingInterface.logException(LoggingInterface.ERROR, e2);
1467: }
1468: }
1469: }
1470: catch(Exception e)
1471: {
1472: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.DATABASE,
1473: "Problem in deleteSessionDataLoop...");
1474: loggingInterface.logException(LoggingInterface.ERROR, e);
1475: }
1476: persistenceInterface.delete("DSSession3Home","getID()='"+sessionDatabaseID+"'");
1477: }
1478: catch(Exception e3)
1479: {
1480: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.DATABASE,
1481: "Problem in deleteSessionDataLoop...");
1482: loggingInterface.logException(LoggingInterface.ERROR, e3);
1483: }
1484: dataLoopFinished = true;
1485: }
1486:
1487: /**
1488: * this method will delete any sessions that do not have saved data. If data
1489: * is not being saved (i.e. no database, etc.), no action is taken. This method
1490: * should not be called if there are active consumers in any of the channels as it
1491: * will not gracefully remove them (call shutdownConnectionsAndThreads first). Also
1492: * note that this method will not clean up the sessionTable by removing the sessions
1493: * whose data has been deleted. This method is designed to be called at shutdown to
1494: * clean up the database prior to the next startup of the DataShare server.
1495: */
1496: void deleteEmptySessions() {
1497: if (useDatabase) {
1498: loggingInterface
1499: .debugMsg(loggingInterface.DEBUG,
1500: loggingInterface.CLIENT,
1501: "Removing Sessions from database if no data was saved...");
1502: for (Enumeration enumS = sessionTable.elements(); enumS
1503: .hasMoreElements();) {
1504: boolean isSavingData = false; // until we find a channel that saves data
1505: SessionInfo si = (SessionInfo) enumS.nextElement();
1506: Hashtable channelTable = si.getChannelTable();
1507: for (Enumeration enumC = channelTable.elements(); enumC
1508: .hasMoreElements();) {
1509: ChannelInfo ci = (ChannelInfo) enumC.nextElement();
1510: if (ci.getSaveDataForThisChannel()) {
1511: isSavingData = true;
1512: break;
1513: }
1514: }
1515: if (!isSavingData) // then we delete it
1516: {
1517: loggingInterface.debugMsg(loggingInterface.DEBUG,
1518: loggingInterface.CLIENT,
1519: "Deleting database data for Session -> "
1520: + si.getName());
1521: deleteSessionData(si.getDatabaseID());
1522: }
1523: }
1524: }
1525: }
1526:
1527: /**
1528: * This is called when we lose a client's commandStatus connection to our server
1529: */
1530: public void connectionLost(SocketAdapter ts) {
1531: loggingInterface.debugMsg(loggingInterface.DEBUG,
1532: loggingInterface.CLIENT,
1533: "Lost the commandStatus connection to "
1534: + ts.getKeyValue());
1535:
1536: // do all the paperwork associated with loosing this client from the commandStatus Channel
1537: if (connections.containsKey(ts.getKeyValue())) {
1538: loggingInterface.debugMsg(loggingInterface.DEBUG,
1539: loggingInterface.CLIENT, "Removing connection for "
1540: + ts.getKeyValue()
1541: + " from connections table");
1542: connections.remove(ts.getKeyValue());
1543: }
1544:
1545: if (ts.getClientKey() != null) {
1546: removeClient(ts.getClientKey());
1547: } else {
1548: loggingInterface
1549: .debugMsg(loggingInterface.DEBUG,
1550: loggingInterface.CLIENT,
1551: "Could not remove client from our tables, socket had no clientKey!");
1552: }
1553:
1554: }
1555:
1556: /**
1557: * called when we need to shutdown all client connections and threads (i.e. we are exiting)
1558: */
1559: public void
1560: shutDownConnectionsAndThreads()
1561: {
1562: if(!alreadyShuttingDown)
1563: {
1564: alreadyShuttingDown = true;
1565: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.GENERALSTATUS,
1566: "Shutting down all connections and Threads...");
1567: // first close all CommandStatus connections that have not been activated
1568: for(Enumeration enum = connections.elements(); enum.hasMoreElements(); )
1569: {
1570: SocketAdapter sa = null;
1571: try{
1572: sa = (SocketAdapter)enum.nextElement();
1573: sa.close();
1574: }
1575: catch(Exception e)
1576: {
1577: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
1578: "Problem shutting down un-activated connection -> " + sa.getKeyValue());
1579: loggingInterface.logException(LoggingInterface.ERROR, e);
1580: }
1581: }
1582:
1583: for(Enumeration enum = allDataReceiverAdapters.elements(); enum.hasMoreElements(); )
1584: {
1585: DataReceiverAdapter dra = null;
1586: try{
1587: dra = (DataReceiverAdapter)enum.nextElement();
1588: // now close all activated CommandStatus connections
1589: dra.stopAllConnectionsAndThreads();
1590: }
1591: catch(Exception e)
1592: {
1593: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
1594: "Problem shutting down data connection -> " + dra.getChannelKey());
1595: loggingInterface.logException(LoggingInterface.ERROR, e);
1596: }
1597: }
1598:
1599: for(Enumeration enum = commandStatusSocketHandlers.elements(); enum.hasMoreElements(); )
1600: {
1601: SocketAdapter sa = null;
1602: try{
1603: sa = (SocketAdapter)enum.nextElement();
1604: sa.close();
1605: }
1606: catch(Exception e)
1607: {
1608: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
1609: "Problem shutting down command/status connection -> " + sa.getKeyValue());
1610: loggingInterface.logException(LoggingInterface.ERROR, e);
1611: }
1612: }
1613:
1614: // now close our CommandStatus Server Thread
1615: if(commandStatusServerThread != null)
1616: commandStatusServerThread.close();
1617: deleteEmptySessions();
1618: }
1619: }
1620:
1621: /**
1622: * This is called when we lose our serverSocket, we can no longer make new connections,
1623: * and may have lost the ability to use old ones for this socket. This particular serverSocket
1624: * is the overall commandStatusPort connection socket.
1625: */
1626: public void lostServerSocket(String keyValue) {
1627: loggingInterface
1628: .debugMsg(loggingInterface.ERROR,
1629: loggingInterface.GENERALSTATUS,
1630: "******* DataShareServer:Lost our commandStatusPort listening socket!!!!!!");
1631: this .shutDownConnectionsAndThreads();
1632: }
1633:
1634: /**
1635: * called when someone new connects to our commandStatus Connection.
1636: * At this point, we know IP and port, but not who is using it.
1637: * ThreadedSocket is saved in Hashtable keyed by clientKey (unique Client name)
1638: */
1639: public void newConnection(SocketAdapter ts) {
1640: loggingInterface.debugMsg(loggingInterface.DEBUG,
1641: loggingInterface.NETWORK,
1642: "New CommandStatus Connection-> " + ts.getKeyValue());
1643: connections.put(ts.getKeyValue(), ts);
1644: }
1645:
1646: /**
1647: * Takes client username, makes it unique, puts client's unique name into our
1648: * Hashtable of clients, keeps a copy of what machine IP they registered from,
1649: * and sends back to the client information about their unique name and server info.
1650: * Note that all clients must have unique clientKey, even clients of dissimilar classes/types
1651: */
1652: public ServerInfo addClient(RegistrationInfo ri, SocketAdapter ts) {
1653: //UserProxy userproxy = null;
1654: StringBuffer errorMsg = new StringBuffer("");
1655: //String uniqueName;
1656: //boolean admin = false;
1657: ServerInfo serverInfo = null; // sent back to client
1658: boolean localUseBeans = persistData;
1659: UserInfo userInfo = null;
1660:
1661: if (logInAdapterFound && authenticatingClients) // we have a way for users to log in and we are authenticating
1662: userInfo = logInInterface.getUserInfo(ri, ts);
1663: else { // for some reason, we will not ask clients to login
1664: userInfo = new UserInfo(ri); // user gets default values for everything
1665: if (!authenticatingClients) // everybody that finds us is considered authenticated!
1666: userInfo.authenticated = true;
1667: }
1668:
1669: if (userInfo.authenticated) {
1670: // client is OK to register
1671: userInfo.uniqueName = getUniqueName(ri.clientUserName);
1672:
1673: // create description of this client's commandStatus connection
1674: DataShareConnectionDescriptor dscd = new DataShareConnectionDescriptor(
1675: "", commandStatusDescriptor.channelDescription,
1676: userInfo.uniqueName, myIPAddress,
1677: this .commandStatusPort, ts.getRemoteIP(), ts
1678: .getRemotePort());
1679: loggingInterface.debugMsg(loggingInterface.DEBUG,
1680: loggingInterface.CLIENT, "Authorizing client "
1681: + userInfo.uniqueName + " with"
1682: + (userInfo.admin ? "" : "out")
1683: + " admin privileges");
1684: connections.remove(ts.getKeyValue());
1685:
1686: ts.setClientKey(userInfo.uniqueName);
1687: ts.setClientClass(userInfo.getClientClass());
1688: ts.setAdmin(userInfo.admin);
1689: ts.setActive(true);
1690:
1691: ClientInfo clientInfo = new ClientInfo(dscd, userInfo,
1692: localUseBeans);
1693:
1694: if (localUseBeans) {
1695: // save data for this client
1696: try {
1697: Hashtable props = new Hashtable();
1698: props.put("clientName", userInfo.uniqueName);
1699: props.put("userObject", clientInfo);
1700: saveDataToDatabase("DSClient3Home", props,
1701: clientInfo);
1702: } catch (Exception e) {
1703: loggingInterface.debugMsg(loggingInterface.ERROR,
1704: loggingInterface.CLIENT,
1705: "Problems creating Client data for "
1706: + userInfo.uniqueName);
1707: loggingInterface.logException(
1708: loggingInterface.ERROR, e);
1709: }
1710: }
1711:
1712: loggingInterface.debugMsg(loggingInterface.DEBUG,
1713: loggingInterface.CLIENT, "Adding this client ("
1714: + userInfo.uniqueName
1715: + ") to our specialClientTable");
1716: specialClientTable.put(userInfo.uniqueName.toLowerCase(),
1717: clientInfo);
1718:
1719: treeView.addSpecialClient(clientInfo);
1720:
1721: loggingInterface
1722: .debugMsg(loggingInterface.DEBUG,
1723: loggingInterface.CLIENT,
1724: "Adding this clients ThreadedSocket to our list of commandStatus clients...");
1725: commandStatusSocketHandlers.put(userInfo.uniqueName, ts);
1726: serverInfo = new ServerInfo(true, userInfo.admin,
1727: userInfo.uniqueName, persistData, serverVersion,
1728: serverStartTime, myIPAddress, this .debug);
1729: } else {
1730: loggingInterface.debugMsg(loggingInterface.WARNING,
1731: loggingInterface.CLIENT,
1732: "Client cannot be authenticated!!!-> "
1733: + ri.clientUserName);
1734: // client is NOT OK to register
1735: serverInfo = new ServerInfo(
1736: false,
1737: false,
1738: "",
1739: false,
1740: "Client "
1741: + ri.clientUserName
1742: + " not known to server\nServer refuses connection.",
1743: serverStartTime, myIPAddress, this .debug);
1744: }
1745: return serverInfo;
1746: }
1747:
1748: /**
1749: * Returns the InetAddress as a String
1750: */
1751: private String getTheMachineName(InetAddress clientIP) {
1752: String machineName = "";
1753: try {
1754: machineName = clientIP.getHostAddress();
1755: } catch (Exception e) {
1756: loggingInterface.debugMsg(loggingInterface.ERROR,
1757: loggingInterface.CLIENT,
1758: "Problems getting IP address of a client");
1759: loggingInterface.logException(loggingInterface.ERROR, e);
1760: }
1761: return machineName;
1762: }
1763:
1764: /**
1765: * removes all references to a Client, takes care of closing its connections and
1766: * notifying other Clients.
1767: */
1768: public void removeClient(String clientKeyValue) {
1769: loggingInterface.debugMsg(loggingInterface.DEBUG,
1770: loggingInterface.CLIENT, "Removing client "
1771: + clientKeyValue + " from all our Hashtables");
1772:
1773: if (specialClientTable
1774: .containsKey(clientKeyValue.toLowerCase())) {
1775: ClientInfo clientInfo = (ClientInfo) specialClientTable
1776: .get(clientKeyValue.toLowerCase());
1777:
1778: if (commandStatusSocketHandlers.containsKey(clientKeyValue)) {
1779: SocketAdapter ts = (SocketAdapter) commandStatusSocketHandlers
1780: .get(clientKeyValue);
1781: treeView.removeTreeListener(ts);
1782: commandStatusSocketHandlers.remove(clientKeyValue); // remove client's handler for commandStatus connection
1783: } else {
1784: loggingInterface.debugMsg(loggingInterface.DEBUG,
1785: loggingInterface.CLIENT,
1786: "no commandStatus table client entry with key of "
1787: + clientKeyValue);
1788: }
1789:
1790: specialClientTable.remove(clientKeyValue.toLowerCase());
1791: treeView.removeSpecialClient(clientInfo);
1792:
1793: // need to find all the Channels this client is in and remove client
1794: if (sessionTable != null) {
1795: for (Enumeration e = sessionTable.elements(); e
1796: .hasMoreElements();) {
1797: SessionInfo this SessionInfo = (SessionInfo) e
1798: .nextElement();
1799: if (this SessionInfo.getChannelTable() != null) {
1800: for (Enumeration channelEnum = this SessionInfo
1801: .getChannelTable().elements(); channelEnum
1802: .hasMoreElements();) {
1803: ChannelInfo this ChannelInfo = (ChannelInfo) channelEnum
1804: .nextElement();
1805: if (this ChannelInfo.getConsumerTable() != null) {
1806: for (Enumeration consumerEnum = this ChannelInfo
1807: .getConsumerTable().elements(); consumerEnum
1808: .hasMoreElements();) {
1809: ConsumerInfo consumerInfo = (ConsumerInfo) consumerEnum
1810: .nextElement();
1811: if (consumerInfo.getKeyValue()
1812: .equals(clientKeyValue)) {
1813: // we found our client as a consumer...
1814: this .removeConsumer(
1815: clientKeyValue,
1816: this SessionInfo
1817: .getKeyValue(),
1818: this ChannelInfo
1819: .getKeyValue());
1820: }
1821: }
1822: }
1823: }
1824: }
1825: }
1826: }
1827: } else {
1828: loggingInterface.debugMsg(loggingInterface.DEBUG,
1829: loggingInterface.CLIENT,
1830: "no client in SpecialClientTable with key of "
1831: + clientKeyValue);
1832: }
1833: }
1834:
1835: /**
1836: * Called when a new consumer had been detected on a ThreadedServer socket (this is called
1837: * from DataReceiverAdapter instances via the TreeViewServerInterface), puts the consumer in
1838: * the list of consumers for the channel, notifies all registered clients, and creates the
1839: * consumer EJB if not already created.
1840: */
1841: public void addConsumer(String clientKey, String sessionKey,
1842: String channelKey, boolean channelActive) {
1843: loggingInterface.debugMsg(loggingInterface.DEBUG,
1844: loggingInterface.CLIENT, "addConsumer(" + clientKey
1845: + "," + sessionKey + "," + channelKey + ")");
1846: ClientInfo clientInfo = (ClientInfo) specialClientTable
1847: .get(clientKey.toLowerCase());
1848: if (clientInfo == null) {
1849: loggingInterface.debugMsg(loggingInterface.DEBUG,
1850: loggingInterface.CLIENT,
1851: "addConsumer() could not add consumer->"
1852: + clientKey
1853: + " because specialClient not found!");
1854: } else {
1855: // now we have a reference to the ClientInfo...
1856: SessionInfo sessionInfo = (SessionInfo) sessionTable
1857: .get(sessionKey);
1858: if (sessionInfo == null) {
1859: loggingInterface.debugMsg(loggingInterface.DEBUG,
1860: loggingInterface.CLIENT,
1861: "addConsumer() could not add consumer->"
1862: + clientKey
1863: + " because Session not found!");
1864: } else {
1865: // now we have a reference to the clientInfo and the sessionInfo...
1866: Hashtable channelTable = sessionInfo.getChannelTable();
1867: if (channelTable == null) {
1868: loggingInterface
1869: .debugMsg(
1870: loggingInterface.DEBUG,
1871: loggingInterface.CLIENT,
1872: "addConsumer() could not add consumer->"
1873: + clientKey
1874: + " because no Channels in Session!");
1875: } else {
1876: ChannelInfo channelInfo = (ChannelInfo) channelTable
1877: .get(channelKey);
1878: // now we have reference to the Channels...
1879: if (channelInfo == null) {
1880: loggingInterface
1881: .debugMsg(
1882: loggingInterface.DEBUG,
1883: loggingInterface.CLIENT,
1884: "addConsumer() could not add consumer->"
1885: + clientKey
1886: + " because could not find the Channel!");
1887: } else {
1888: // now we have a reference to the specific channel...
1889: ConsumerInfo consumerInfo = new ConsumerInfo(
1890: clientInfo, sessionInfo, channelInfo);
1891: consumerInfo.setActive(channelActive);
1892:
1893: // add or overwrite channel table and tree entries
1894: loggingInterface
1895: .debugMsg(
1896: loggingInterface.DEBUG,
1897: loggingInterface.CLIENT,
1898: "server.addConsumer() adding "
1899: + consumerInfo
1900: .getKeyValue()
1901: + " as "
1902: + (consumerInfo
1903: .getActive() ? "active"
1904: : "inactive")
1905: + " to Session ("
1906: + sessionInfo.getName()
1907: + "), Channel ("
1908: + channelInfo.getName()
1909: + ")");
1910: channelInfo.addConsumerClient(consumerInfo);
1911: treeView.addConsumer(consumerInfo); // notifies clients so they update their trees
1912: }
1913: }
1914: }
1915: }
1916: }
1917:
1918: /**
1919: * Called when a consumer closes a Channel connection for which the server cannot
1920: * detect that the connection is closed (i.e. UDP), this will remove the consumer from
1921: * our tables, our tree, and cause the connection to close for that client in that channel
1922: */
1923: public void removeAndDisconnectConsumer(String clientKey,
1924: String sessionKey, String channelKey) {
1925: SessionInfo sessionInfo = (SessionInfo) sessionTable
1926: .get(sessionKey);
1927: if (sessionInfo == null) {
1928: loggingInterface
1929: .debugMsg(
1930: loggingInterface.DEBUG,
1931: loggingInterface.CLIENT,
1932: "removeAndDisconnectConsumer() could not remove consumer because Session not found!");
1933: } else {
1934: // now we have a reference to the clientInfo and the sessionInfo...
1935: Hashtable channelTable = sessionInfo.getChannelTable();
1936: if (channelTable == null) {
1937: loggingInterface
1938: .debugMsg(
1939: loggingInterface.DEBUG,
1940: loggingInterface.CLIENT,
1941: "removeAndDisconnectConsumer() could not remove consumer because no Channels in Session!");
1942: } else {
1943: ChannelInfo channelInfo = (ChannelInfo) channelTable
1944: .get(channelKey);
1945: // now we have reference to the Channels...
1946: if (channelInfo == null) {
1947: loggingInterface
1948: .debugMsg(
1949: loggingInterface.DEBUG,
1950: loggingInterface.CLIENT,
1951: "removeAndDisconnectConsumer() could not remove consumer because could not find the Channel!");
1952: } else {
1953: // now we have a reference to the specific channel...
1954: Hashtable consumerTable = channelInfo
1955: .getConsumerTable();
1956: if (consumerTable == null) {
1957: loggingInterface
1958: .debugMsg(
1959: loggingInterface.DEBUG,
1960: loggingInterface.CLIENT,
1961: "removeAndDisconnectConsumer() could not remove consumer because channel has no consumers!");
1962: } else {
1963: ConsumerInfo consumerInfo = (ConsumerInfo) consumerTable
1964: .get(clientKey);
1965: if (consumerInfo != null) {
1966: channelInfo
1967: .removeConsumerClient(consumerInfo);
1968: treeView.removeConsumer(consumerInfo);
1969: // if no more consumers and this is a channel in an 'autoDelete' Session,
1970: // the channel is deleted from the database and the Session
1971: if (consumerTable.isEmpty()
1972: && sessionInfo.getAutoDelete()) {
1973: loggingInterface
1974: .debugMsg(
1975: loggingInterface.DEBUG,
1976: loggingInterface.SESSION,
1977: "Channel ("
1978: + channelInfo
1979: .getName()
1980: + ") is empty in autoDelete Session ("
1981: + sessionInfo
1982: .getName()
1983: + "), removing it...");
1984: channelTable.remove(channelKey);
1985: channelInfo.shutDown();
1986: treeView.removeChannel(channelInfo);
1987: }
1988: } else {
1989: loggingInterface
1990: .debugMsg(
1991: loggingInterface.DEBUG,
1992: loggingInterface.SESSION,
1993: "removeAndDisconnectConsumer("
1994: + clientKey
1995: + ") could not remove consumer because this consumer was not in Channel ("
1996: + channelInfo
1997: .getName()
1998: + ")");
1999: }
2000: }
2001: }
2002: }
2003: }
2004: }
2005:
2006: /**
2007: * Called when a consumer had closed a Channel connection (this is called
2008: * from DataReceiverAdapter instances via the TreeViewServerInterface)
2009: */
2010: public void removeConsumer(String clientKey, String sessionKey,
2011: String channelKey) {
2012: // get a reference to the SessionInfo...
2013: SessionInfo sessionInfo = (SessionInfo) sessionTable
2014: .get(sessionKey);
2015: if (sessionInfo == null) {
2016: loggingInterface
2017: .debugMsg(
2018: loggingInterface.DEBUG,
2019: loggingInterface.CLIENT,
2020: "removeConsumer("
2021: + clientKey
2022: + ") could not remove consumer because Session ("
2023: + sessionKey + ") not found!");
2024: } else {
2025: // now find a reference to the ChannelInfo...
2026: Hashtable channelTable = sessionInfo.getChannelTable();
2027: if (channelTable == null) {
2028: loggingInterface
2029: .debugMsg(
2030: loggingInterface.DEBUG,
2031: loggingInterface.CLIENT,
2032: "removeConsumer("
2033: + clientKey
2034: + ") could not remove consumer because no Channels in Session!");
2035: } else {
2036: ChannelInfo channelInfo = (ChannelInfo) channelTable
2037: .get(channelKey);
2038: // now we have reference to the Channels...
2039: if (channelInfo == null) {
2040: loggingInterface
2041: .debugMsg(
2042: loggingInterface.DEBUG,
2043: loggingInterface.CLIENT,
2044: "removeConsumer("
2045: + clientKey
2046: + ") could not remove consumer because could not find the Channel!");
2047: } else {
2048: // now we have a reference to the specific channel...
2049: Hashtable consumerTable = channelInfo
2050: .getConsumerTable();
2051: if (consumerTable == null
2052: || consumerTable.isEmpty()) {
2053: loggingInterface
2054: .debugMsg(
2055: loggingInterface.DEBUG,
2056: loggingInterface.CLIENT,
2057: "removeConsumer("
2058: + clientKey
2059: + ") could not remove consumer because channel has no conusmers!");
2060: } else {
2061: ConsumerInfo consumerInfo = (ConsumerInfo) consumerTable
2062: .get(clientKey);
2063: if (consumerInfo != null) {
2064: loggingInterface
2065: .debugMsg(
2066: loggingInterface.DEBUG,
2067: loggingInterface.CLIENT,
2068: "Removing consumer "
2069: + clientKey
2070: + " from server table for Session/Channel of "
2071: + sessionKey + "/"
2072: + channelKey);
2073: consumerTable.remove(clientKey);
2074: treeView.removeConsumer(consumerInfo); // send updates to clients
2075:
2076: // if no more consumers and this is a channel in an autoDelete Session,
2077: // remove the channel from the session
2078: if (channelInfo.getConsumerTable()
2079: .isEmpty()
2080: && sessionInfo.getAutoDelete()) {
2081: loggingInterface
2082: .debugMsg(
2083: loggingInterface.DEBUG,
2084: loggingInterface.SESSION,
2085: "Channel("
2086: + channelKey
2087: + ") in autoDelete Session("
2088: + sessionKey
2089: + ") is now empty, removing it...");
2090: sessionInfo.getChannelTable().remove(
2091: channelInfo.getKeyValue());
2092: channelInfo.shutDown();
2093: treeView.removeChannel(channelInfo);
2094: }
2095:
2096: // just to make double sure, tell the client to remove the function on it's end,
2097: // just in case an error was detected on this server and not on the client end also.
2098: if (this .commandStatusSocketHandlers
2099: .containsKey(clientKey)) {
2100: // find the command/status connection for this client
2101: SocketAdapter ts = (SocketAdapter) commandStatusSocketHandlers
2102: .get(clientKey);
2103: if (ts != null) {
2104: // create and send the disconnect command to the client for this session/channel/consumer
2105: try {
2106: DisconnectConsumer dc = new DisconnectConsumer(
2107: clientKey, sessionInfo
2108: .getName(),
2109: channelInfo.getName());
2110: DataShareObject dso = new DataShareObject(
2111: SessionUtilities
2112: .convertObjectToByteArray(dc),
2113: DataShareObject.SENDTOALL,
2114: this .myClientKeyValue);
2115: ts.sendData(dso); // use this client's commandStatusConnection
2116: } catch (Exception e) {
2117: }
2118: }
2119: }
2120: } else {
2121: loggingInterface
2122: .debugMsg(
2123: loggingInterface.DEBUG,
2124: loggingInterface.CLIENT,
2125: "removeConsumer("
2126: + clientKey
2127: + ") could not remove consumer because session/channel("
2128: + sessionKey
2129: + "/"
2130: + channelKey
2131: + ") had no such consumer!");
2132: }
2133: }
2134: }
2135: }
2136: }
2137: }
2138:
2139: /**
2140: * Used to create a Session that contains the Channels described by the CreateSessionRequest object.
2141: */
2142: public ClientSessionInfo
2143: createSession(SocketAdapter ts, CreateSessionRequest csr)
2144: {
2145: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2146: "Creating Session " + csr.sessionName);
2147:
2148: boolean validClient = false;
2149: String clientName = ""; // this is the client userName (chuck), not the unique name (chuck-2), so they can go back later and delete the session no matter how they log-in
2150: String clientKeyValue = ts.getClientKey();
2151: InetAddress clientAddress = ts.getRemoteIP(); // address of client
2152: ClientSessionInfo clientSessionInfo = null;
2153: SessionInfo sessionInfo = null;
2154: boolean foundSession = false;
2155:
2156: // make sure clientKey has registered and is calling from same machine...
2157: ClientInfo clientInfo = (ClientInfo)specialClientTable.get(clientKeyValue.toLowerCase());
2158:
2159: if(clientInfo != null)
2160: {
2161: InetAddress clientInet = clientInfo.getHostMachine();
2162: clientName = clientInfo.getName();
2163:
2164: // check to see if the IP address client registered from is the one sending this request...
2165: if(clientInet.getHostAddress().equals(ts.getRemoteIP().getHostAddress()))
2166: validClient = true;
2167: else
2168: loggingInterface.debugMsg(loggingInterface.WARNING,loggingInterface.GENERALSTATUS,
2169: "createSession() aborting: client on different IP, was ("+clientInet.getHostAddress()+"), now ("+ts.getRemoteIP().getHostAddress()+")");
2170: }
2171: else
2172: loggingInterface.debugMsg(loggingInterface.WARNING,loggingInterface.SESSION,
2173: "createSession() will not create session, could not find the requesting client("+clientName+")!");
2174:
2175: if(validClient)
2176: {
2177: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.CLIENT,
2178: "Client("+clientInfo.getName()+") is valid");
2179: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2180: "Client("+clientInfo.getName()+") requested the following channels: ");
2181: for(int x=0; x< csr.desiredChannels.channelDescriptions.length; x++)
2182: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2183: " - " + csr.desiredChannels.channelDescriptions[x].channelName);
2184:
2185: if(csr.joinIfAlreadyExists) // then we should go look for a session like the csr session
2186: {
2187: // if we find a Session like the one to be created, save it in sessionInfo attribute
2188:
2189: // create temporary SessionInfo like one we want to create
2190: // except that it has no Channels!!!!!!
2191: SessionInfo si = new SessionInfo(csr.sessionName, // may need to check for unique session names here, i.e. check if we match -01, -02, etc.
2192: csr.sessionDescription,
2193: clientName,
2194: clientInfo.getClientClass(),
2195: persistData);
2196: SessionInfo si2 = null;
2197:
2198: // try to find a Session like the one we are asked to create...
2199: // need to set sessionInfo to correct value and foundSession to true
2200: for(Enumeration enum = getSessionTable().elements(); enum.hasMoreElements();)
2201: {
2202: si2 = (SessionInfo)enum.nextElement();
2203: if(si2.isSubSet(si)) // see if si is subset of si2
2204: {
2205: sessionInfo = si2;
2206: foundSession = true;
2207: break;
2208: }
2209: }
2210: if(sessionInfo != null)
2211: {
2212: // now check that all channel names already exists, otherwise we will need to create the channel
2213: for(int x=0; x< csr.desiredChannels.channelDescriptions.length; x++)
2214: {
2215: if(!sessionInfo.getChannelTable().containsKey(csr.desiredChannels.channelDescriptions[x].channelName))
2216: {
2217: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2218: "creating missing channel: ");
2219: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2220: " channelName=" + csr.desiredChannels.channelDescriptions[x].channelName);
2221: ChannelInfo this Channel = createChannel(csr.desiredChannels.channelDescriptions[x],
2222: sessionInfo);
2223: sessionInfo.addChannel(this Channel);
2224: treeView.addChannel(this Channel);
2225: }
2226: }
2227: }
2228: }
2229:
2230: if(sessionInfo == null)
2231: {
2232: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2233: "A new unique Session will be created...");
2234: // ensure that Session name is unique...
2235: // Session name MUST BE UNIQUE, we use it as a Key now
2236: // save info about this session...
2237: sessionInfo = new SessionInfo(getUniqueSessionName(csr.sessionName),
2238: csr.sessionDescription,
2239: clientName,
2240: clientInfo.getClientClass(),
2241: persistData);
2242: //sessionInfo.saveData = allowArchiving;
2243: sessionInfo.privateSession = csr.sessionIsPrivate;
2244: if(csr.autoDelete)
2245: sessionInfo.setAutoDelete();
2246:
2247: if(persistData)
2248: {
2249: try{
2250: Hashtable props = new Hashtable();
2251: props.put("sessionName", sessionInfo.getName());
2252: props.put("userObject", sessionInfo);
2253: saveDataToDatabase("DSSession3Home", props, sessionInfo); // ADSKey will evenutally get into this SessionInfo
2254: // delay here until Key is filled in...this is a blocking call
2255: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.DATABASE,
2256: "waiting for session EJB to be returned for " + sessionInfo.getName());
2257: String key = sessionInfo.getDatabaseID();
2258:
2259: }
2260: catch(Exception e)
2261: {
2262: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.DATABASE,
2263: "Problems creating Session Bean for " + sessionInfo.getName());
2264: loggingInterface.logException(loggingInterface.ERROR, e);
2265: }
2266: }
2267:
2268: sessionTable.put(sessionInfo.getKeyValue(),sessionInfo);
2269: // tell clients about new session...
2270: treeView.addSession(sessionInfo);
2271:
2272: for(int x=0; x<csr.desiredChannels.channelDescriptions.length; x++)
2273: {
2274: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2275: "creating channel: ");
2276: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2277: " channelName=" + csr.desiredChannels.channelDescriptions[x].channelName);
2278:
2279: ChannelInfo this Channel = createChannel(csr.desiredChannels.channelDescriptions[x],
2280: sessionInfo);
2281: sessionInfo.addChannel(this Channel);
2282: treeView.addChannel(this Channel);
2283: }
2284: }
2285:
2286: // create object to send to requesting client
2287: clientSessionInfo = new ClientSessionInfo(sessionInfo.getName(),
2288: sessionInfo.getSessionDescription(),
2289: sessionInfo.getKeyValue(),
2290: sessionInfo.getChannelConnectionDescriptors(),
2291: !foundSession, sessionInfo.getPrivate()); // new session, private type
2292: }
2293: else
2294: {
2295: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
2296: "Client "+clientName+" is not valid, not creating session " + csr.sessionName);
2297: }
2298:
2299: return clientSessionInfo;
2300: }
2301:
2302: /**
2303: * Creates the DataReceiverAdapter for this channel, so the Channel is fully up and working
2304: * when this method returns. We don't need to call TreeView here because it is assumed
2305: * that this method is part of a createSession call and that the createSession call will
2306: * take care of updating the TreeView. If we later need a reference to the DataReceiverAdapter,
2307: * we can use the ChannelInfo to get it.
2308: */
2309: private ChannelInfo createChannel(ChannelDescription cd,
2310: SessionInfo sessionInfo, boolean saveTheData) {
2311: ChannelInfo channelInfo = null;
2312: DataShareConnectionDescriptor dscd = null;
2313:
2314: // dra won't have serverThread entry yet...
2315: DataReceiverAdapter dra = new DataReceiverAdapter(this );
2316: allDataReceiverAdapters.add(dra);
2317:
2318: switch (cd.type) {
2319: case ChannelDescription.TCP:
2320: // make receiving Threads a higher priority
2321: TcpSocketServer serverThread = new TcpSocketServer(dra,
2322: getNextPort(),
2323: SessionUtilities.SocketRcvDataPriority);
2324: dra.setSocketServer((SocketServerInterface) serverThread); // now dra has socket server
2325: dscd = new DataShareConnectionDescriptor(sessionInfo
2326: .getName(), cd, this .myIPAddress, serverThread
2327: .getLocalPort());
2328: serverThread.start();
2329: while (!serverThread.getReady()) {
2330: loggingInterface.debugMsg(loggingInterface.DEBUG,
2331: loggingInterface.NETWORK,
2332: "waiting for network connection to be available for session "
2333: + sessionInfo.getName() + "...");
2334: SessionUtilities.delay(100);
2335: }
2336: break;
2337: case ChannelDescription.UDP:
2338: UdpSocketServer serverThread2 = new UdpSocketServer(
2339: myIPAddress, (DataReceiverInterface) dra,
2340: getNextPort(),
2341: SessionUtilities.SocketRcvDataPriority);
2342: dra.setSocketServer(serverThread2); // now dra has socket server
2343: dscd = new DataShareConnectionDescriptor(sessionInfo
2344: .getName(), cd, this .myIPAddress, serverThread2
2345: .getLocalPort());
2346: serverThread2.start();
2347: while (!serverThread2.getReady()) {
2348: loggingInterface.debugMsg(loggingInterface.DEBUG,
2349: loggingInterface.NETWORK,
2350: "waiting for network connection to be available for session "
2351: + sessionInfo.getName() + "...");
2352: SessionUtilities.delay(100);
2353: }
2354: break;
2355: case ChannelDescription.MULTICAST:
2356: MulticastSocketServer serverThread3 = new MulticastSocketServer(
2357: getMulticastIPAddress(),
2358: (DataReceiverInterface) dra, getNextPort(),
2359: SessionUtilities.SocketRcvDataPriority);
2360: dra.setSocketServer(serverThread3); // now dra has socket server
2361: dscd = new DataShareConnectionDescriptor(sessionInfo
2362: .getName(), cd, getMulticastIPAddress(),
2363: serverThread3.getLocalPort());
2364: serverThread3.start();
2365: while (!serverThread3.getReady()) {
2366: loggingInterface.debugMsg(loggingInterface.DEBUG,
2367: loggingInterface.NETWORK,
2368: "waiting for network connection to be available for session "
2369: + sessionInfo.getName() + "...");
2370: SessionUtilities.delay(100);
2371: }
2372: break;
2373: }
2374:
2375: channelInfo = new ChannelInfo(dscd, dra, sessionInfo,
2376: saveTheData);
2377: dra.setChannelInfo(channelInfo);
2378: dra.setSessionInfo(sessionInfo);
2379:
2380: // create an EJB for this Channel (if we are using Beans)
2381: if (saveTheData && sessionInfo.saveData) {
2382: try {
2383: Hashtable props = new Hashtable();
2384: props.put("sessionKey", sessionInfo.getDatabaseID()); // was ADSKey
2385: props.put("channelName", channelInfo
2386: .getConnectionDescriptor().name);
2387: props.put("userObject", channelInfo);
2388: saveDataToDatabase("DSChannel3Home", props, channelInfo);
2389: // wait for EJB to be created...this will block!
2390: loggingInterface.debugMsg(loggingInterface.DEBUG,
2391: loggingInterface.DATABASE,
2392: "waiting for channel EJB to be returned for Session/Channel ("
2393: + sessionInfo.getName() + "/"
2394: + channelInfo.getName() + ")");
2395: String key = channelInfo.getDatabaseID();
2396: dscd.databaseID = key;
2397: } catch (Exception e) {
2398: loggingInterface.debugMsg(loggingInterface.ERROR,
2399: loggingInterface.NETWORK,
2400: "Problems creating Channel Bean for Session/Channel ("
2401: + sessionInfo.getName() + "/"
2402: + channelInfo.getName() + ")");
2403: loggingInterface
2404: .logException(loggingInterface.ERROR, e);
2405: }
2406: }
2407:
2408: return channelInfo;
2409: }
2410:
2411: /**
2412: * Creates the DataReceiverAdapter for this channel, so Channel is full up and working
2413: * when this method returns. We don't need to call TreeView here because it is assumed
2414: * that this method is part of a createSession call and that the createSession call will
2415: * take care of updating the TreeView. If we later need a reference to the DataReceiverAdapter,
2416: * we can use the ChannelInfo to get it.
2417: */
2418: private ChannelInfo createChannel(ChannelDescription cd,
2419: SessionInfo sessionInfo) {
2420: return createChannel(cd, sessionInfo, persistData);
2421: }
2422:
2423: /**
2424: * Used to retrieve a Multicast IP address, we arbitrarily just pick one
2425: */
2426: private InetAddress getMulticastIPAddress() {
2427: InetAddress multicastIP = null;
2428: try {
2429: multicastIP = InetAddress.getByName(multiCastIPaddress);
2430: if (!multicastIP.isMulticastAddress())
2431: loggingInterface.debugMsg(loggingInterface.ERROR,
2432: loggingInterface.NETWORK,
2433: "Problems -> not a valid multicast IP -> "
2434: + multiCastIPaddress);
2435: } catch (Exception e) {
2436: loggingInterface.debugMsg(loggingInterface.ERROR,
2437: loggingInterface.NETWORK,
2438: "Problems getting our multicastIP ("
2439: + multiCastIPaddress + ") by name...");
2440: loggingInterface.logException(loggingInterface.ERROR, e);
2441: }
2442: return multicastIP;
2443: }
2444:
2445: /**
2446: * Creates the DataReceiverAdapter for this channel, so Channel is full up and working
2447: * when this method returns. This method is called when a new channel is to be added to
2448: * a Session that already exists. NOT IMPLEMENTED YET
2449: */
2450: private ChannelInfo addNewChannel(ChannelDescription cd,
2451: SessionInfo sessionInfo) {
2452: return (ChannelInfo) null;
2453: }
2454:
2455: /**
2456: * used to provide the next port number to use for a Channel connection. Currently, no distinction
2457: * is made between a UDP and a TCP connection (we could have UDP and TCP use the same port for
2458: * different sockets).
2459: */
2460: public synchronized int getNextPort() {
2461: if (++currentPort > lastPort) {
2462: loggingInterface
2463: .debugMsg(
2464: loggingInterface.WARNING,
2465: loggingInterface.NETWORK,
2466: "All Session Ports used once - You may require multiple Sessions on a port, or more ports allocated...\n"
2467: + "<<<<<*>>>>>Trying to wrap around and re-use ports...");
2468: currentPort = firstPort;
2469: }
2470: return currentPort;
2471: }
2472:
2473: /**
2474: * Takes a name as a parameter and returns a version of the name that is guaranteed
2475: * to be unique in our list of Clients. If the name is not already in our
2476: * list, it is simply returned. If the name is already in the Client list,
2477: * it is modified slightly to make it unique.
2478: *
2479: * @param name the client name to be used as the basis for creating a
2480: * unique name
2481: */
2482: private synchronized String getUniqueName(String name) {
2483: boolean finished = false;
2484: String newName = name;
2485: int counter = 2;
2486: loggingInterface.debugMsg(loggingInterface.DEBUG,
2487: loggingInterface.CLIENT, "getUniqueName() called for "
2488: + name);
2489: while (!finished) {
2490: if (specialClientTable.containsKey(newName.toLowerCase())) {
2491: newName = name + "-" + counter++;
2492: } else {
2493: finished = true; // name is unique
2494: loggingInterface.debugMsg(loggingInterface.DEBUG,
2495: loggingInterface.CLIENT,
2496: "getUniqueName(): returning-> " + newName);
2497: }
2498: }
2499: return newName;
2500: }
2501:
2502: /**
2503: * Takes a name as a parameter and returns a version of the name that is guaranteed
2504: * to be unique in our list of Sessions. If the name is not already in our
2505: * list, it is simply returned. If the name is already in the Session list,
2506: * it is modified slightly to make it unique.
2507: *
2508: * @param name the Session name to be used as the basis for creating a
2509: * unique name
2510: */
2511: private synchronized String getUniqueSessionName(String name) {
2512: boolean finished = false;
2513: String newName = name;
2514: int counter = 2;
2515: loggingInterface.debugMsg(loggingInterface.DEBUG,
2516: loggingInterface.SESSION,
2517: "getUniqueSessionName() called for " + name);
2518: while (!finished) {
2519: if (sessionTable != null
2520: && sessionTable.containsKey(newName)) {
2521: // try another name
2522: newName = name + "-" + counter++;
2523: } else {
2524: finished = true; // no Sessions to look at
2525: loggingInterface.debugMsg(loggingInterface.DEBUG,
2526: loggingInterface.SESSION,
2527: "getUniqueSessionName() returning " + newName);
2528: }
2529: }
2530: return newName;
2531: }
2532:
2533: /**
2534: * @param clientKey keyValue of client to be checked for Admin privileges
2535: * @return true if client has Admin privileges, false otherwise
2536: */
2537: public boolean isClientAdmin(String clientKey) {
2538: boolean retValue = false;
2539: // find ClientInfo for this client...
2540: if (specialClientTable.containsKey(clientKey.toLowerCase())) {
2541: ClientInfo ci = (ClientInfo) specialClientTable
2542: .get(clientKey.toLowerCase());
2543: retValue = ci.getAdmin();
2544: } else {
2545: loggingInterface.debugMsg(loggingInterface.DEBUG,
2546: loggingInterface.CLIENT,
2547: "isClientAdmin() could not find client -> "
2548: + clientKey);
2549: }
2550: return retValue;
2551: }
2552:
2553: /**
2554: * Used to determine if this server instance supports persisting data
2555: *
2556: * @return true if server supports persisting data, false otherwise
2557: */
2558: public boolean getPersistData() {
2559: return persistData;
2560: }
2561:
2562: /**
2563: * returns reference to persistence interface, should be non-null if getPersistData() returns true,
2564: * may be null otherwise
2565: */
2566: public PersistenceInterface getPersistenceInterface() {
2567: return this .persistenceInterface;
2568: }
2569:
2570: /**
2571: * Returns true if this client is in the list of clients who have registered, false otherwise
2572: */
2573: public boolean isClientRegistered(String clientKey) {
2574: boolean retValue = false;
2575: if (specialClientTable.containsKey(clientKey.toLowerCase()))
2576: retValue = true;
2577: return retValue;
2578: }
2579:
2580: /**
2581: * Returns the ClientInfo for this client is this client is found in specialClients table,
2582: * or null if not found
2583: */
2584: public ClientInfo getClientInfo(String clientKey) {
2585: ClientInfo retValue = null;
2586: if (specialClientTable.containsKey(clientKey.toLowerCase()))
2587: retValue = (ClientInfo) specialClientTable.get(clientKey
2588: .toLowerCase());
2589: return retValue;
2590: }
2591:
2592: /**
2593: * This method saveds the specified data to the database and puts the data's key value into the
2594: * PersistDataCallbackInterface instance after the data is created.
2595: *
2596: * @param tableName the name of the table this data should be added to
2597: * @param props describes what is to be persisted in the database
2598: * @param callback the interface that supplies the methods used to set the Key for this data
2599: */
2600: public void saveDataToDatabase(String tableName, Hashtable props,
2601: PersistDataCallbackInterface callback) {
2602: loggingInterface.debugMsg(loggingInterface.DEBUG,
2603: loggingInterface.DATABASE,
2604: "--saveDataToDatabase(): queueing " + tableName
2605: + " EJB");
2606: persistDataQueue.write(new PersistDataQueueObject(tableName,
2607: props, callback));
2608: }
2609:
2610: /**
2611: * called from the Fifo thread when data is available in the FIFO. Data was put into
2612: * the FIFO by the persistDataQueue.write() method. This is called when the Fifo thread has
2613: * finished with waiting for the previous database key to be created?
2614: */
2615: public void newFifoDataAvailable(Object obj) {
2616: //ADSKey ak = null;
2617: PersistDataQueueObject myObject = (PersistDataQueueObject) obj;
2618: if (myObject != null) {
2619: if (myObject.getCallback() != null)
2620: myObject.getCallback().setWaitingForKey(true);
2621:
2622: //ADSObject ao = EjbUtil.create(myObject.tableName, myObject.getProperties());
2623: String newKeyString = persistenceInterface.save(myObject
2624: .getTableName(), myObject.getProperties());
2625:
2626: if (newKeyString != null) {
2627: loggingInterface.debugMsg(loggingInterface.DEBUG,
2628: loggingInterface.DATABASE, "--data created: "
2629: + myObject.getTableName() + "."
2630: + newKeyString);
2631: if (myObject.getCallback() != null)
2632: myObject.getCallback().setDatabaseID(newKeyString); // save a way to get the EJB again
2633: } else
2634: loggingInterface.debugMsg(loggingInterface.WARNING,
2635: loggingInterface.DATABASE,
2636: "problems creating data, save did not return key value for "
2637: + myObject.getTableName());
2638: }
2639: }
2640:
2641: /**
2642: * returns the table of clients
2643: */
2644: public Hashtable getSpecialClientTable() {
2645: return this .specialClientTable;
2646: }
2647:
2648: /**
2649: * returns the table of sessions
2650: */
2651: public Hashtable getSessionTable() {
2652: return this .sessionTable;
2653: }
2654:
2655: /**
2656: * returns the ChannelInfo specified by the supplied ADSKey String
2657: */
2658: private ChannelInfo getChannelInfo(String channelDatabaseID) {
2659: ChannelInfo retValue = null;
2660: if (this .persistData) {
2661: boolean found = false;
2662: for (Enumeration sessionsEnum = sessionTable.elements(); sessionsEnum
2663: .hasMoreElements()
2664: && !found;) {
2665: SessionInfo si = (SessionInfo) sessionsEnum
2666: .nextElement();
2667: Hashtable channelTable = si.getChannelTable();
2668: for (Enumeration channelsEnum = channelTable.elements(); channelsEnum
2669: .hasMoreElements();) {
2670: ChannelInfo ci = (ChannelInfo) channelsEnum
2671: .nextElement();
2672: if (ci.getDatabaseID().equals(channelDatabaseID)) {
2673: retValue = ci;
2674: found = true; // causes us to exit outer loop
2675: break; // causes us to exit inner loop, we are done
2676: }
2677: }
2678: }
2679: } else
2680: loggingInterface
2681: .debugMsg(loggingInterface.WARNING,
2682: loggingInterface.DATABASE,
2683: " *** cannot call getChannelInfo(databaseID) method when not saving data!!");
2684: return retValue;
2685: }
2686:
2687: /// the token scheme may need synchronized tables because these methods are called from
2688: /// many different threads (Hashtables are thread safe, right?)
2689:
2690: /**
2691: * TokenReqest objects indexed by tokenKey
2692: */
2693: Hashtable tokens = new Hashtable();
2694:
2695: /**
2696: * if a client has to wait for a token, their request goes into this item.
2697: * want to use linked list so we can better manage taking items out of the
2698: * middle and append to the end.
2699: */
2700: List waitingForTokens = Collections
2701: .synchronizedList(new LinkedList());
2702:
2703: /**
2704: * this is called whenever we receive a TokenRequestObject from a Client, this
2705: * method will take care of managing the Tokens for each Channel.
2706: * @param tro the Request
2707: * @param ts the client's commandStatusConnection SocketAdapter
2708: */
2709: private synchronized void tokenRequestReceived(
2710: TokenRequestObject tro, SocketAdapter ts) {
2711: DataShareObject dso = null;
2712: try {
2713: loggingInterface
2714: .debugMsg(
2715: loggingInterface.DEBUG,
2716: loggingInterface.CLIENT,
2717: "Client "
2718: + ts.getClientKey()
2719: + " sent Token "
2720: + tro.tokenKey
2721: + " with value of "
2722: + TokenRequestObject.typeOfRequestStrings[tro.typeOfRequest]);
2723:
2724: switch (tro.typeOfRequest) {
2725: case TokenRequestObject.REQUEST:
2726: // determine if the client is active in the channel...only for REQUESTs
2727: SessionInfo si = (SessionInfo) sessionTable
2728: .get(tro.sessionName); // sessionName is also key for sessionTable
2729: SocketAdapter sa = null;
2730: if (si != null) {
2731: ChannelInfo ci = (ChannelInfo) si.getChannelTable()
2732: .get(tro.channelName);
2733: if (ci != null) {
2734: ConsumerInfo consumerInfo = (ConsumerInfo) ci
2735: .getConsumerTable().get(
2736: ts.getClientKey());
2737: if (consumerInfo != null) {
2738: DataReceiverAdapter dra = ci
2739: .getDataReceiverAdapter();
2740: sa = dra.findConsumerSocket(consumerInfo);
2741: } else {
2742: loggingInterface.debugMsg(
2743: loggingInterface.WARNING,
2744: loggingInterface.CLIENT,
2745: "RequestToken could not find consumer ("
2746: + ts.getClientKey()
2747: + ") to send token to");
2748: }
2749: } else {
2750: loggingInterface.debugMsg(
2751: loggingInterface.WARNING,
2752: loggingInterface.CLIENT,
2753: "RequestToken could not find channel ("
2754: + tro.channelName
2755: + ") for client ("
2756: + ts.getClientKey() + ")");
2757: }
2758: } else {
2759: loggingInterface.debugMsg(loggingInterface.WARNING,
2760: loggingInterface.CLIENT,
2761: "RequestToken could not find session ("
2762: + tro.sessionName
2763: + ") for client ("
2764: + ts.getClientKey() + ")");
2765: }
2766:
2767: if (sa != null && sa.getActive()) {
2768: if (tokens.containsKey(tro.tokenKey)) {
2769: // a client already has the token
2770: TokenRequest tr = (TokenRequest) tokens
2771: .get(tro.tokenKey);
2772: loggingInterface.debugMsg(
2773: loggingInterface.DEBUG,
2774: loggingInterface.CLIENT, "Client "
2775: + tr.clientKeyValue
2776: + " already has Token "
2777: + tro.tokenKey);
2778: // check to see if same client is requesting it again
2779: if (ts.getClientKey().equals(tr.clientKeyValue)) {
2780: loggingInterface.debugMsg(
2781: loggingInterface.DEBUG,
2782: loggingInterface.CLIENT, "Client ("
2783: + ts.getClientKey()
2784: + ") is requesting Token ("
2785: + tro.tokenKey + ") again");
2786: } else // a client has the Token, and it is not requesting client
2787: {
2788: // check to see if current client has had Token too long
2789: if (tr.expireDate.before(new Date())) {
2790: // we have passed the expire date, REVOKE it from one client and GRANT it to the requestor
2791: loggingInterface
2792: .debugMsg(
2793: loggingInterface.DEBUG,
2794: loggingInterface.CLIENT,
2795: "Token ("
2796: + tro.tokenKey
2797: + ") has been held by Client ("
2798: + tr.clientKeyValue
2799: + ") too long, Revoking it");
2800: // issue REVOKE
2801: dso = new DataShareObject(
2802: SessionUtilities
2803: .convertObjectToByteArray(new TokenRequestObject(
2804: TokenRequestObject.REVOKE,
2805: tro.tokenKey)),
2806: tr.ts.getType(),
2807: tr.clientKeyValue);
2808: tr.ts.sendData(dso);
2809: tokens.remove(tro.tokenKey); // remove the current Token holder
2810: loggingInterface.debugMsg(
2811: loggingInterface.DEBUG,
2812: loggingInterface.CLIENT,
2813: "Granting Token "
2814: + tro.tokenKey
2815: + " to Client "
2816: + ts.getClientKey());
2817: // issue GRANT
2818: dso = new DataShareObject(
2819: SessionUtilities
2820: .convertObjectToByteArray(new TokenRequestObject(
2821: TokenRequestObject.GRANT,
2822: tro.tokenKey)),
2823: ts.getType(), ts.getClientKey());
2824: ts.sendData(dso);
2825: // save info about who we are giving the token to...
2826: tokens.put(tro.tokenKey,
2827: new TokenRequest(ts
2828: .getClientKey(), ts,
2829: tro.tokenKey));
2830: } else // requesting client has to wait for current client to give up Token...
2831: {
2832: // make sure they are not already waiting...
2833: int index = this
2834: .findWaitingRequest(
2835: tro.tokenKey, ts
2836: .getClientKey());
2837: if (index >= 0) // if already waiting, update timer then put client back into waiting
2838: {
2839: loggingInterface
2840: .debugMsg(
2841: loggingInterface.DEBUG,
2842: loggingInterface.CLIENT,
2843: "Client "
2844: + ts
2845: .getClientKey()
2846: + " was already waiting for Token "
2847: + tro.tokenKey
2848: + ", removing first instance...");
2849: waitingForTokens.remove(index);
2850: }
2851: loggingInterface
2852: .debugMsg(
2853: loggingInterface.DEBUG,
2854: loggingInterface.CLIENT,
2855: "Client "
2856: + ts
2857: .getClientKey()
2858: + " will have to wait for Token "
2859: + tro.tokenKey
2860: + " add them to waiting list");
2861: waitingForTokens.add(new TokenRequest(
2862: ts.getClientKey(), ts,
2863: tro.tokenKey));
2864: }
2865: }
2866: } else {
2867: // no client already has the token
2868: // save info about who we are giving the token to...
2869: loggingInterface.debugMsg(
2870: loggingInterface.DEBUG,
2871: loggingInterface.CLIENT,
2872: "No client has Token " + tro.tokenKey
2873: + ", so issuing it to "
2874: + ts.getClientKey());
2875: tokens.put(tro.tokenKey, new TokenRequest(ts
2876: .getClientKey(), ts, tro.tokenKey));
2877: dso = new DataShareObject(
2878: SessionUtilities
2879: .convertObjectToByteArray(new TokenRequestObject(
2880: TokenRequestObject.GRANT,
2881: tro.tokenKey)), ts
2882: .getType(), ts.getClientKey());
2883: ts.sendData(dso);
2884: }
2885: } else
2886: loggingInterface
2887: .debugMsg(loggingInterface.WARNING,
2888: loggingInterface.CLIENT,
2889: "Igonoring TokenRequest from Consumer whose socket is not active");
2890: break;
2891: case TokenRequestObject.CANCEL:
2892: // cannot assume that cancel came from client that had it!
2893: TokenRequest currentHolder = (TokenRequest) tokens
2894: .get(tro.tokenKey);
2895: if (currentHolder != null) {
2896: // test to see if CANCEL came from currentHolder...
2897: if (ts.getClientKey().equals(
2898: currentHolder.clientKeyValue)) {
2899: loggingInterface.debugMsg(
2900: loggingInterface.DEBUG,
2901: loggingInterface.CLIENT, "Client "
2902: + ts.getClientKey()
2903: + " has released Token "
2904: + tro.tokenKey);
2905: tokens.remove(tro.tokenKey); // if a client already has the token, remove it
2906: // see if anybody is waiting for the Token...
2907: int index = this
2908: .findWaitingRequest(tro.tokenKey);
2909: if (index >= 0) // if a Client is waiting, give it to them
2910: {
2911: TokenRequest tr = (TokenRequest) waitingForTokens
2912: .remove(index);
2913: loggingInterface.debugMsg(
2914: loggingInterface.DEBUG,
2915: loggingInterface.CLIENT, "Client "
2916: + tr.ts.getClientKey()
2917: + " was waiting for Token "
2918: + tro.tokenKey
2919: + ", Grant them the Token");
2920: // issue GRANT
2921: dso = new DataShareObject(
2922: SessionUtilities
2923: .convertObjectToByteArray(new TokenRequestObject(
2924: TokenRequestObject.GRANT,
2925: tro.tokenKey)),
2926: tr.ts.getType(), tr.ts
2927: .getClientKey());
2928: tr.ts.sendData(dso);
2929: // save info about who we are giving the token to...
2930: tokens.put(tro.tokenKey, new TokenRequest(
2931: tr.ts.getClientKey(), tr.ts,
2932: tro.tokenKey));
2933: } else {
2934: loggingInterface.debugMsg(
2935: loggingInterface.DEBUG,
2936: loggingInterface.CLIENT,
2937: "No client was waiting for Token "
2938: + tro.tokenKey);
2939: }
2940: } else {
2941: loggingInterface
2942: .debugMsg(
2943: loggingInterface.DEBUG,
2944: loggingInterface.CLIENT,
2945: "Client "
2946: + ts.getClientKey()
2947: + " Canceled Token "
2948: + tro.tokenKey
2949: + ", is not the current Holder...");
2950: int index = this .findWaitingRequest(
2951: tro.tokenKey, ts.getClientKey());
2952: if (index >= 0) // if waiting, remove client from waiting
2953: {
2954: loggingInterface
2955: .debugMsg(
2956: loggingInterface.DEBUG,
2957: loggingInterface.CLIENT,
2958: "Client "
2959: + ts.getClientKey()
2960: + " was waiting for Token "
2961: + tro.tokenKey
2962: + ", removed from waiting list");
2963: waitingForTokens.remove(index);
2964: }
2965: }
2966: } else {
2967: loggingInterface.debugMsg(loggingInterface.DEBUG,
2968: loggingInterface.CLIENT,
2969: "No client was Granted Token "
2970: + tro.tokenKey
2971: + ", but we received a Cancel!!");
2972: }
2973: break;
2974: default:
2975: loggingInterface.debugMsg(loggingInterface.WARNING,
2976: loggingInterface.CLIENT,
2977: "Received incorrect typeOfRequest: "
2978: + tro.typeOfRequest);
2979: } // end of switch
2980: } // end of try
2981: catch (Exception e) {
2982: loggingInterface.debugMsg(loggingInterface.ERROR,
2983: loggingInterface.CLIENT,
2984: "Problems in TokenRequestReceived():");
2985: loggingInterface.logException(LoggingInterface.ERROR, e);
2986: }
2987: }
2988:
2989: /**
2990: * looks for the specified token request in our list of waiting clients, returns
2991: * the index into waitingForTokens if found, -1 otherwise. This should only be
2992: * called from the synchronized method tokenRequestReceived.
2993: */
2994: private int findWaitingRequest(String tokenKey) {
2995: loggingInterface.debugMsg(loggingInterface.DEBUG,
2996: loggingInterface.CLIENT,
2997: "Is a client waiting for Token " + tokenKey + "?");
2998:
2999: int retValue = -1;
3000: for (int x = 0; x < waitingForTokens.size(); x++) {
3001: TokenRequest tr = (TokenRequest) waitingForTokens.get(x);
3002: loggingInterface.debugMsg(loggingInterface.DEBUG,
3003: loggingInterface.CLIENT, "Found client "
3004: + tr.clientKeyValue + " waiting for Token "
3005: + tr.tokenKey);
3006: if (tr.tokenKey.equals(tokenKey)) {
3007: // found this request!
3008: retValue = x;
3009: loggingInterface.debugMsg(loggingInterface.DEBUG,
3010: loggingInterface.CLIENT,
3011: "Found a client waiting for this Token!");
3012: break;
3013: }
3014: }
3015: return retValue;
3016: }
3017:
3018: /**
3019: * looks for the specified token request in our list of waiting clients, returns
3020: * the index into waitingForTokens if this client is found to be waiting for this Token,
3021: * -1 otherwise. This should only be called from the synchronized method tokenRequestReceived.
3022: */
3023: private int findWaitingRequest(String tokenKey,
3024: String clientKeyValue) {
3025: int retValue = -1;
3026: for (int x = 0; x < waitingForTokens.size(); x++) {
3027: TokenRequest tr = (TokenRequest) waitingForTokens.get(x);
3028: if (tr.clientKeyValue.equals(clientKeyValue)
3029: && tr.tokenKey.equals(tokenKey)) {
3030: // found this request!
3031: retValue = x;
3032: break;
3033: }
3034: }
3035: return retValue;
3036: }
3037:
3038: /**
3039: * This method loads the ChannelDescription array that we use to tell the clients
3040: * what functions they are allowed to use in Sessions. We try to load
3041: * our functions file name from a property in the normal system config file.
3042: */
3043: private void
3044: getChannelDescriptionsFromConfigFile()
3045: {
3046: Vector channels = new Vector();
3047: ChannelDescription cd = null;
3048: ChannelDescription channelDescriptions[] = null;
3049: try{
3050: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
3051: "Retrieving our function descriptions from a file...");
3052: String fn = channelTypesFile; // value set by default or PropertiesManager
3053: if(fn.length() == 0 || fn.equals(""))
3054: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
3055: "No file specified for the channel descriptions, only BroadCastClients will work, not Rendezvous");
3056: else
3057: {
3058: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
3059: "Trying to read channel description file " + fn );
3060: FileReader fr = null;
3061: try{
3062: fr = new FileReader(fn);
3063: }
3064: catch(FileNotFoundException fnfe)
3065: {
3066: // see if the classloader can find it
3067: fn = this .getClass().getClassLoader().getResource(fn).getFile();
3068: if(fn == null)
3069: {
3070: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
3071: "No file specified for channel descriptions");
3072: Enumeration enum = this .getClass().getClassLoader().getResources(fn);
3073: while(enum.hasMoreElements())
3074: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,
3075: "Found resource " + enum.nextElement());
3076: }
3077:
3078: // next line will generate an error and kick us out if we still cannot find the file
3079: loggingInterface.debugMsg(loggingInterface.WARNING,loggingInterface.SESSION,
3080: "Now trying to read channel description file " + fn );
3081: fr = new FileReader(fn);
3082: }
3083:
3084: BufferedReader din = new BufferedReader(fr);
3085: String line;
3086: int tokenCount =0;
3087: while ((line=din.readLine())!= null)
3088: {
3089: try{
3090: // skip any lines that start with #
3091: if(!line.trim().startsWith("#"))
3092: {
3093: StringTokenizer st = new StringTokenizer(line, ";");
3094: tokenCount = st.countTokens();
3095: if (tokenCount < 10) // must be at least 10 tokens or it is a comment line
3096: continue;
3097: // after here must be 10 or more
3098: String name = st.nextToken().trim(); // name must be unique among all channels
3099: String className = st.nextToken().trim();
3100: String description = st.nextToken().trim();
3101: String connectionType = st.nextToken().trim();
3102: String jarFile = st.nextToken().trim();
3103: boolean allowPersistSelection = new Boolean( st.nextToken().toLowerCase().trim()).booleanValue();
3104: boolean persistPreSet = new Boolean( st.nextToken().toLowerCase().trim()).booleanValue();
3105: boolean selectionPreSet = new Boolean( st.nextToken().toLowerCase().trim()).booleanValue();
3106: int historyDelay = Integer.parseInt(st.nextToken().trim());
3107: int historyCountInc = Integer.parseInt(st.nextToken().trim());
3108:
3109: if(!persistData)
3110: allowPersistSelection = false; // no more archiving!!!
3111:
3112: StringBuffer sb = new StringBuffer();
3113: sb.append("name-"+name+ "\n class-" + className + "\n description-" + description + "\n type-" + connectionType + "\n jar-" + jarFile +
3114: "\n allowHistory-" + allowPersistSelection + "\n persist-" + persistPreSet + "\n selection-" + selectionPreSet +
3115: "\n historyDelay-" + historyDelay + "\n historyCountIncrement-" + historyCountInc);
3116:
3117: if (tokenCount > 10) // does this entry contain optional MIME information for archiving?
3118: {
3119: String mimeType = st.nextToken().trim();
3120: String fileExtension = st.nextToken().trim();
3121: String mimeClassName = st.nextToken().trim();
3122: String setMethod = st.nextToken().trim();
3123: String getMethod = st.nextToken().trim();
3124: cd = new ChannelDescription(name,className,description,connectionType,jarFile,allowPersistSelection,persistPreSet,selectionPreSet,historyDelay,historyCountInc,
3125: mimeType,fileExtension,mimeClassName,setMethod,getMethod);
3126: sb.append(" mimeType-"+mimeType+ "\n extension-" + fileExtension + "\n className-" + mimeClassName + "\n set-" + setMethod + "\n get-" + getMethod);
3127: }
3128: else // must be == 10 (no archive support)
3129: {
3130: cd = new ChannelDescription(name,className,description,connectionType,jarFile,allowPersistSelection,persistPreSet,selectionPreSet,historyDelay,historyCountInc);
3131: }
3132: loggingInterface.debugMsg(loggingInterface.DEBUG,loggingInterface.SESSION,sb.toString());
3133: if(cd != null)
3134: {
3135: channels.add(cd);
3136: }
3137: }
3138: }
3139: catch(Exception e)
3140: {
3141: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
3142: "Problems reading channel config file...");
3143: loggingInterface.logException(LoggingInterface.ERROR, e);
3144: }
3145: } // end of while loop
3146: din.close();
3147:
3148: if(channels.size() > 0)
3149: {
3150: channelDescriptions = new ChannelDescription[channels.size()];
3151: for(int x=0; x<channels.size(); x++)
3152: {
3153: channelDescriptions[x] = (ChannelDescription)channels.elementAt(x);
3154: }
3155: // now save it
3156: channelDescriptionArray = new ChannelDescriptionArray(channelDescriptions);
3157: }
3158: else
3159: {
3160: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
3161: "Could not find any Channel/Functions to send to clients!!");
3162: //this.shutDownConnectionsAndThreads();
3163: }
3164: }
3165: }
3166: catch(Exception e)
3167: {
3168: loggingInterface.debugMsg(loggingInterface.ERROR,loggingInterface.SESSION,
3169: "Problems trying to get functions/channel descriptions...");
3170: loggingInterface.logException(LoggingInterface.ERROR, e);
3171: }
3172: }
3173:
3174: public String getServerInfo() {
3175: return serverInfoString;
3176: }
3177:
3178: public boolean getShowArchivedSessionsToAdmin() {
3179: return showArchivedSessionsToAdmin;
3180: }
3181:
3182: } // end of class
3183:
3184: /********************/
3185:
3186: class TokenRequest {
3187: final static int expireTimeInSeconds = 30;
3188: Date currentDate = new Date();
3189: Date expireDate = null; // the time at which this client has held the Token too long
3190: String clientKeyValue = null;
3191: SocketAdapter ts = null;
3192: String tokenKey = null;
3193:
3194: /**
3195: * constructor, used when we grant a Token, also provides a time value used to
3196: * determine if a Client's use of the Token, or request of a Token should expire
3197: * @param clientKeyValue the client that we are giving the Token to
3198: * @param ts the commandStatusConnection for the client we are giving the Token to
3199: */
3200: TokenRequest(String clientKeyValue, SocketAdapter ts,
3201: String tokenKey) {
3202: expireDate = new Date(currentDate.getTime()
3203: + expireTimeInSeconds * 1000);
3204: this.clientKeyValue = clientKeyValue;
3205: this.ts = ts;
3206: this.tokenKey = tokenKey;
3207: }
3208:
3209: }
|