0001:/*
0002: * Copyright (c) 2001 Silvere Martin-Michiellot All Rights Reserved.
0003: *
0004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
0005: * royalty free, license to use, modify and redistribute this
0006: * software in source and binary code form,
0007: * provided that i) this copyright notice and license appear on all copies of
0008: * the software; and ii) Licensee does not utilize the software in a manner
0009: * which is disparaging to Silvere Martin-Michiellot.
0010: *
0011: * This software is provided "AS IS," without a warranty of any kind. ALL
0012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
0013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
0014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
0015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
0016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
0017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
0018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
0019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
0020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
0021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
0022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
0023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
0024: *
0025: * This software is not designed or intended for use in on-line control of
0026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
0027: * the design, construction, operation or maintenance of any nuclear
0028: * facility. Licensee represents and warrants that it will not use or
0029: * redistribute the Software for such purposes.
0030: *
0031: * @Author: Silvere Martin-Michiellot
0032: *
0033: */
0034:
0035:package com.db.server;
0036:
0037:
0038:import com.db.client.ServerHelper;
0039:import com.db.net.*;
0040:
0041:import java.io.*;
0042:import java.lang.IllegalArgumentException;
0043:import java.net.*;
0044:import java.security.*;
0045:import java.util.*;
0046:import java.util.zip.*;
0047:import javax.jdo.*;
0048:import javax.media.j3d.*;
0049:import javax.vecmath.*;
0050:import javax.net.*;
0051:import javax.net.ssl.*;
0052:import com.sun.net.ssl.*;
0053:
0054://import com.sun.jdori.*;
0055://import com.sun.jdori.common.*;
0056:
0057:
0058:import com.sun.j3d.utils.scenegraph.io.*;
0059:
0060:/**
0061: * This is the black box of the server side. It provides network and database capabilities but no GUI interface.
0062: */
0063:
0064:Quetzalcoatl (aztec god, brother of Tezcatlipoca)
0065:Viracocha (inca god)
0066:Itzamna (maya god)
0067:
0068:public class UniverseServer extends Object implements Runnable {
0069:
0070: /**
0071: * IP
0072: * Port
0073: * information (if a virtual world is to be described using World Spots on different servers, the informations should always
0074: * be the same):
0075: * Date
0076: * Creator author Name, E-mail, Public Key
0077: * Given name for Universe
0078: * Version
0079: * local World Spot list (stored using a database)
0080: * server list:
0081: * servers of connected World Spots
0082: * IP
0083: * Port
0084: * remote World Spot list information:
0085: * position and orientation
0086: * encompass
0087: * informations
0088: * ruler
0089: * gates to other known virtual worlds
0090: * IP
0091: * Port
0092: * current time relative to Greenwich Mean Time (should be as accurate as possible) (used to compute timers) (your favorite
0093: * watch might actually show you what it wants)
0094: */
0095:
0096: private static final String SECURED = "TLS";
0097: private static final String PLAINSOCKET = "PlainSocket";
0098: private static final boolean clientAuthentification = true;
0099: private static int connectionQueue = 50;
0100: public static int DefaultServerPort = 7777;
0101:
0102: private ServerSocket serverSocket;
0103:
0104: //private FOStorePMF fOStorePMF;
0105: private PersistenceManager persistenceManager;
0106:
0107: public final static String STRING_DATE = "Date";
0108: public final static String STRING_CREATOR_NAME = "Creator Name";
0109: public final static String STRING_CREATOR_E_MAIL = "Creator e-mail";
0110: public final static String STRING_CREATOR_PUBLIC_KEY = "Creator Public Key";
0111: public final static String STRING_NAME = "Name";
0112: public final static String STRING_VERSION = "Version";
0113:
0114: private LoginInformation loginInformation;
0115: private InetAddress IP;
0116: private int port;
0117: private Hashtable information;
0118: private HashSet localWorldSpots;
0119: private HashSet remoteServers;
0120: private HashSet gates;
0121: private long time;
0122: private long offset;
0123: private boolean activeLog;
0124:
0125: public UniverseServer() {
0126:
0127: throw new java.lang.IllegalArgumentException("A universe server must have a login, a password and at least a WorldSpot.");
0128:
0129: }
0130:
0131: public UniverseServer(LoginInformation loginInformation, WorldSpot worldSpot) throws IOException {
0132:
0133: this (loginInformation, InetAddress.getLocalHost(), UniverseServer.DefaultServerPort, worldSpot);
0134:
0135: }
0136:
0137: public UniverseServer(LoginInformation loginInformation, InetAddress inetAddress, WorldSpot worldSpot) throws IOException {
0138:
0139: this (loginInformation, inetAddress, UniverseServer.DefaultServerPort, worldSpot);
0140:
0141: }
0142:
0143: public UniverseServer(LoginInformation loginInformation, InetAddress inetAddress, int port, WorldSpot worldSpot) throws IOException {
0144:
0145: ServerSocketFactory serverSocketFactory;
0146: Avatar ruler;
0147:
0148: activeLog = false;
0149:
0150: this .loginInformation = loginInformation;
0151:
0152: ruler = this .createRuler(loginInformation);
0153:
0154: this .IP = inetAddress;
0155: this .port = port;
0156:
0157: //database part
0158:
0159: //fOStorePMF = new FOStorePMF();
0160: //YYYYYYYYYYYYYYYYY
0161: //persistenceManager = PersistenceManagerFactory.getPersistenceManager();
0162: this .addLocalWorldSpot(worldSpot);
0163:
0164: //Network part
0165: // try {
0166: serverSocketFactory = this .getServerSocketFactory(UniverseServer.PLAINSOCKET);
0167: serverSocket = serverSocketFactory.createServerSocket(port, connectionQueue, IP);
0168:
0169: if (clientAuthentification) {
0170: ((SSLServerSocket)serverSocket).setNeedClientAuth(true);
0171: }
0172: this .newListener();
0173:
0174: //} catch (IOException iOException) {
0175: // System.out.println("Unable to start Server: " +
0176: // iOException.getMessage());
0177: // iOException.printStackTrace();
0178: //}
0179:
0180: }
0181:
0182: public final PersistenceManager getPersistenceManager() {
0183:
0184: return this .persistenceManager;
0185:
0186: }
0187:
0188:
0189: //can be called by any requesting application (may be not related directly to digital biosphere company)
0190: public final InetAddress getIP() {
0191:
0192: return this .IP;
0193:
0194: }
0195:
0196: //at start-up time only
0197: //should use local IP
0198: //but there may be physical machines with mutiple IP so this parameter
0199: protected final void setIP(InetAddress IP) {
0200:
0201: this .IP = IP;
0202:
0203: }
0204:
0205: public final int getPort() {
0206:
0207: return this .port;
0208:
0209: }
0210:
0211: //at start-up time only
0212: public final void setPort(int port) {
0213:
0214: this .port = port;
0215:
0216: }
0217:
0218: public final LoginInformation getLoginInformation() {
0219:
0220: return this .loginInformation;
0221:
0222: }
0223:
0224: protected final void setLoginInformation(LoginInformation loginInformation) {
0225:
0226: this .loginInformation = loginInformation;
0227:
0228: }
0229:
0230: public final Hashtable getInformation() {
0231:
0232: information.put(UniverseServer.STRING_DATE, this .getDate());
0233: information.put(UniverseServer.STRING_CREATOR_NAME, this .getCreatorName());
0234: information.put(UniverseServer.STRING_CREATOR_E_MAIL, this .getCreatorEMail());
0235: information.put(UniverseServer.STRING_CREATOR_PUBLIC_KEY, this .getCreatorPublicKey());
0236: information.put(UniverseServer.STRING_NAME, this .getName());
0237: information.put(UniverseServer.STRING_VERSION, this .getVersion());
0238:
0239: return information;
0240:
0241: }
0242:
0243: public final Object getInformation(String key) {
0244:
0245: return information.get(key);
0246:
0247: }
0248:
0249: public final Date getDate() {
0250:
0251: return (Date)this .getInformation(UniverseServer.STRING_DATE);
0252:
0253: }
0254:
0255: public final String getCreatorName() {
0256:
0257: return (String)this .getInformation(UniverseServer.STRING_CREATOR_NAME);
0258:
0259: }
0260:
0261: public final String getCreatorEMail() {
0262:
0263: return (String)this .getInformation(UniverseServer.STRING_CREATOR_E_MAIL);
0264:
0265: }
0266:
0267: public final PublicKey getCreatorPublicKey() {
0268:
0269: return (PublicKey)this .getInformation(UniverseServer.STRING_CREATOR_PUBLIC_KEY);
0270:
0271: }
0272:
0273: public final String getName() {
0274:
0275: return (String)this .getInformation(UniverseServer.STRING_NAME);
0276:
0277: }
0278:
0279: public final String getVersion() {
0280:
0281: return (String)this .getInformation(UniverseServer.STRING_VERSION);
0282:
0283: }
0284:
0285: //asynchronous modification while server running via a GUI side track tool
0286: public final void setDate(Date date) {
0287:
0288: this .addInformation(UniverseServer.STRING_DATE, date.toString());
0289:
0290: }
0291:
0292: //asynchronous modification while server running via a GUI side track tool
0293: public final void setCreatorName(String name) {
0294:
0295: this .addInformation(UniverseServer.STRING_CREATOR_NAME, name);
0296:
0297: }
0298:
0299: //asynchronous modification while server running via a GUI side track tool
0300: public final void setCreatorEMail(String eMail) {
0301:
0302: this .addInformation(UniverseServer.STRING_CREATOR_E_MAIL, eMail);
0303:
0304: }
0305:
0306: //asynchronous modification while server running via a GUI side track tool
0307: public final void setCreatorPublicKey(PublicKey publicKey) {
0308:
0309: this .addInformation(UniverseServer.STRING_CREATOR_PUBLIC_KEY, publicKey.toString());
0310:
0311: }
0312:
0313: //asynchronous modification while server running via a GUI side track tool
0314: public final void setName(String name) {
0315:
0316: this .addInformation(UniverseServer.STRING_NAME, name);
0317:
0318: }
0319:
0320: //asynchronous modification while server running via a GUI side track tool
0321: public final void setVersion(String version) {
0322:
0323: this .addInformation(UniverseServer.STRING_VERSION, version);
0324:
0325: }
0326:
0327: //asynchronous modification while server running via a GUI side track tool
0328: //obliterates every previously stored information including reserved fields
0329: //no check for valid values are made, please be cautious
0330: public final void setInformation(Hashtable information) {
0331:
0332: this .information = information;
0333:
0334: }
0335:
0336: //asynchronous addition while server running via a GUI side track tool
0337: //use the corresponding method to set the individual default fields
0338: public final void addInformation(String key, String keyValue) {
0339:
0340: //check if it is a reserved field or not
0341: if ((key!=UniverseServer.STRING_DATE) && (key!=UniverseServer.STRING_CREATOR_NAME) && (key!=UniverseServer.STRING_CREATOR_E_MAIL) && (key!=UniverseServer.STRING_CREATOR_PUBLIC_KEY) && (key!=UniverseServer.STRING_NAME) && (key!=UniverseServer.STRING_VERSION)) {
0342: this .information.put(key, keyValue);
0343: }
0344: else {
0345: throw new java.lang.IllegalArgumentException("You can't add directely Information on the restricted fields.");
0346: }
0347:
0348: }
0349:
0350: //asynchronous deletion while server running via a GUI side track tool
0351: public final void removeInformation(String key) {
0352:
0353: //check if it is a reserved field or not
0354: if ((key!=UniverseServer.STRING_DATE) && (key!=UniverseServer.STRING_CREATOR_NAME) && (key!=UniverseServer.STRING_CREATOR_E_MAIL) && (key!=UniverseServer.STRING_CREATOR_PUBLIC_KEY) && (key!=UniverseServer.STRING_NAME) && (key!=UniverseServer.STRING_VERSION)) {
0355: this .information.remove(key);
0356: }
0357: else {
0358: throw new java.lang.IllegalArgumentException("You can't remove directely Information on the restricted fields.");
0359: }
0360:
0361: }
0362:
0363: public final HashSet getLocalWorldSpots() {
0364:
0365: Transaction transaction;
0366: Extent extent;
0367: Query query;
0368: HashSet hashSet;
0369:
0370: try {
0371: transaction = this .getPersistenceManager().currentTransaction();
0372: transaction.begin();
0373:
0374: extent = this .getPersistenceManager().getExtent(WorldSpot.class, true);
0375: query = this .getPersistenceManager().newQuery(WorldSpot.class, extent);
0376: hashSet = (HashSet) query.execute();
0377:
0378: transaction.commit();
0379:
0380: return hashSet;
0381:
0382: }
0383: catch (Exception exception) {
0384:
0385: return null;
0386:
0387: }
0388:
0389: }
0390:
0391: //asynchronous addition while server running via a GUI side track tool
0392: //we check bounds are exclusive but not that the new bounds are continuous with the current WorldSpots
0393: //we don't check that the resulting bounds on this server are mutually exclusive with remote servers serving the same virtual world
0394: //proposed ruler must be a new Avatar
0395: public final void addLocalWorldSpot(WorldSpot worldSpot) {
0396:
0397: Transaction transaction;
0398: Extent extent;
0399: Query query;
0400: String filter;
0401: Collection collection;
0402: BoundingPolytope currentBounds;
0403: WorldSpot currentWorldSpot;
0404: Iterator iterator;
0405:
0406: if (worldSpot!=null) {
0407:
0408: try {
0409: transaction = this .getPersistenceManager().currentTransaction();
0410: transaction.begin();
0411:
0412: extent = this .getPersistenceManager().getExtent(WorldSpot.class, true);
0413: filter = new String("SELECT * FROM WorldSpot");
0414: query = this .getPersistenceManager().newQuery(WorldSpot.class, extent, filter);
0415: collection = (Collection) query.execute();
0416:
0417: transaction.commit();
0418:
0419: iterator = collection.iterator();
0420: currentBounds = new BoundingPolytope();
0421:
0422: while (iterator.hasNext()) {
0423: currentWorldSpot = (WorldSpot) iterator.next();
0424: currentBounds.combine(currentWorldSpot.getBounds());
0425: }
0426:
0427: if (!currentBounds.intersect(worldSpot.getBounds())) {
0428:
0429: try {
0430: transaction = this .getPersistenceManager().currentTransaction();
0431: transaction.begin();
0432:
0433: extent = this .getPersistenceManager().getExtent(Avatar.class, true);
0434: filter = new String("SELECT * FROM Avatar WHERE avatar=worldSpot.getRuler()");
0435: query = this .getPersistenceManager().newQuery(Avatar.class, extent, filter);
0436: collection = (Collection) query.execute();
0437:
0438: transaction.commit();
0439: }
0440: catch (Exception exception) {
0441: }
0442:
0443: if (collection.size()>0) {
0444:
0445: transaction = this .getPersistenceManager().currentTransaction();
0446: transaction.begin();
0447:
0448: this .getPersistenceManager().makePersistent(worldSpot.getRuler());
0449:
0450: transaction.commit();
0451: }
0452:
0453: try {
0454: transaction = this .getPersistenceManager().currentTransaction();
0455: transaction.begin();
0456:
0457: this .getPersistenceManager().makePersistent(worldSpot);
0458:
0459: transaction.commit();
0460: }
0461: catch (Exception exception) {
0462: }
0463:
0464: }
0465:
0466: }
0467: catch (Exception exception) {
0468: }
0469:
0470: }
0471:
0472: }
0473:
0474: //users should be kicked off before the World Spot is permanently removed
0475: //asynchronous deletion while server running via a GUI side track tool
0476: public final void removeLocalWorldSpot(WorldSpot worldSpot) {
0477:
0478: Transaction transaction;
0479: Extent extent;
0480: Query query;
0481: String filter;
0482: Collection collection;
0483: Collection avatars;
0484: Iterator iterator;
0485: Avatar avatar;
0486:
0487: if (worldSpot!=null) {
0488:
0489: avatars = worldSpot.getAvatars(worldSpot.getRuler());
0490:
0491: iterator = avatars.iterator();
0492: while (iterator.hasNext()) {
0493: avatar = (Avatar) iterator.next();
0494: avatar.disconnectUser();
0495: }
0496:
0497: try {
0498: transaction = this .getPersistenceManager().currentTransaction();
0499: transaction.begin();
0500:
0501: extent = this .getPersistenceManager().getExtent(VirtualElement.class, true);
0502: filter = new String("SELECT * FROM VirtualElement");
0503: query = this .getPersistenceManager().newQuery(VirtualElement.class, extent, filter);
0504: collection = (Collection) query.execute();
0505:
0506: transaction.commit();
0507:
0508: try {
0509: transaction = this .getPersistenceManager().currentTransaction();
0510: transaction.begin();
0511:
0512: this .getPersistenceManager().deletePersistentAll(collection);
0513: this .getPersistenceManager().deletePersistent(worldSpot);
0514:
0515: transaction.commit();
0516: }
0517: catch (Exception exception) {
0518: }
0519:
0520: }
0521: catch (Exception exception) {
0522: }
0523:
0524: }
0525:
0526: }
0527:
0528: //removes existing then set new
0529: public final void setLocalWorldSpots(HashSet worldSpots) {
0530:
0531: Iterator iterator;
0532:
0533: iterator = this .getLocalWorldSpots().iterator();
0534: while (iterator.hasNext()) {
0535: this .removeLocalWorldSpot((WorldSpot)iterator.next());
0536: }
0537:
0538: iterator = worldSpots.iterator();
0539: while (iterator.hasNext()) {
0540: this .addLocalWorldSpot((WorldSpot)iterator.next());
0541: }
0542:
0543: }
0544:
0545: //callback from worldspot when bounds have changed
0546: protected void notifyBoundsChange(WorldSpot worldSpot) {
0547:
0548: this .notifyLocalWorldSpotUpdate();
0549:
0550: }
0551:
0552: //tell to remote servers that the local world spot list is updated
0553: public final void notifyLocalWorldSpotUpdate() {
0554:
0555: Socket socket;
0556: ObjectOutputStream objectOutputStream;
0557:
0558: HashSet hashSet;
0559: ControlNotification controlNotification;
0560: WorldSpot worldSpot;
0561: WorldSpotBasicInformation worldSpotBasicInformation;
0562: RemoteWorldSpotsAccess remoteWorldSpotsAccess;
0563: Iterator iterator;
0564:
0565: hashSet = new HashSet();
0566:
0567: iterator = this .getLocalWorldSpots().iterator();
0568: while (iterator.hasNext()) {
0569: worldSpot = (WorldSpot) iterator.next();
0570: worldSpotBasicInformation = new WorldSpotBasicInformation(worldSpot.getRuler(), worldSpot.getBounds(), worldSpot.getInformation());
0571: hashSet.add(worldSpotBasicInformation);
0572: }
0573:
0574: iterator = this .getRemoteServers().iterator();
0575: while (iterator.hasNext()) {
0576: //query distant server and fetch informations
0577: //distant server should send information to update
0578: remoteWorldSpotsAccess = (RemoteWorldSpotsAccess)iterator.next();
0579:
0580: //query distant server and fetch informations
0581: try {
0582:
0583: socket = new Socket(this .getIP(), this .getPort(), remoteWorldSpotsAccess.getIP(), remoteWorldSpotsAccess.getPort());
0584:
0585: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
0586:
0587: controlNotification = new ControlNotification(ControlNotification.LOCALWORLDSPOTS, hashSet);
0588: // send request
0589: objectOutputStream.writeObject(controlNotification);
0590:
0591: objectOutputStream.flush();
0592: objectOutputStream.close();
0593:
0594: socket.close();
0595:
0596: }
0597: catch (IOException iOexception) {
0598: }
0599: }
0600:
0601: }
0602:
0603: public final HashSet getRemoteServers() {
0604:
0605: return this .remoteServers;
0606:
0607: }
0608:
0609: //asynchronous addition while server running via a GUI side track tool
0610: public final void setRemoteServers(HashSet remoteServers) {
0611:
0612: this .remoteServers = remoteServers;
0613:
0614: }
0615:
0616: //asynchronous addition while server running via a GUI side track tool
0617: public final void addRemoteServer(RemoteWorldSpotsAccess remoteWorldSpotsAccess) {
0618:
0619: this .remoteServers.add(remoteWorldSpotsAccess);
0620:
0621: }
0622:
0623: //asynchronous deletion while server running via a GUI side track tool
0624: public final void removeRemoteServer(RemoteWorldSpotsAccess remoteWorldSpotsAccess) {
0625:
0626: this .remoteServers.remove(remoteWorldSpotsAccess);
0627:
0628: }
0629:
0630: //Queries the servers to be sure they still serve some WorldSpots
0631: //updates the Remote World Spot List of each of these Remote Servers
0632: //does not delete unreachable servers
0633: //it is up to the user to manually do so by calling first updateRemoteServersList
0634: public final void updateRemoteServers() {
0635:
0636: RemoteWorldSpotsAccess remoteWorldSpotsAccess;
0637: Iterator iterator;
0638:
0639: iterator = this .getRemoteServers().iterator();
0640: while (iterator.hasNext()) {
0641: //query distant server and fetch informations
0642: //distant server should send information to update
0643: remoteWorldSpotsAccess = (RemoteWorldSpotsAccess)iterator.next();
0644: remoteWorldSpotsAccess.updateRemoteWorldSpots(this );
0645: }
0646:
0647: }
0648:
0649: //queries servers and delete unreachable servers
0650: //be cautious before using this method as servers may be only temporary unreachable
0651: public final void updateRemoteServersList() {
0652:
0653: Socket socket;
0654: ObjectOutputStream objectOutputStream;
0655: ObjectInputStream objectInputStream;
0656:
0657: ControlRequest controlRequest;
0658: ControlReply controlReply;
0659: RemoteWorldSpotsAccess remoteWorldSpotsAccess;
0660: Iterator iterator;
0661:
0662: iterator = this .getRemoteServers().iterator();
0663: while (iterator.hasNext()) {
0664: //query distant server and fetch informations
0665: //distant server should send information to update
0666: remoteWorldSpotsAccess = (RemoteWorldSpotsAccess)iterator.next();
0667:
0668: try {
0669:
0670: //query distant server and fetch informations
0671: socket = new Socket(this .getIP(), this .getPort(), remoteWorldSpotsAccess.getIP(), remoteWorldSpotsAccess.getPort());
0672:
0673: objectInputStream = new ObjectInputStream(socket.getInputStream());
0674: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
0675:
0676: controlRequest = new ControlRequest(ControlRequest.INFORMATION);
0677: // send request
0678: objectOutputStream.writeObject(controlRequest);
0679:
0680: // read response
0681: try {
0682:
0683: controlReply = (ControlReply) objectInputStream.readObject();
0684:
0685: if (controlReply.getReplyKind()!=ControlReply.REFUSED) {
0686:
0687: this .removeRemoteServer(remoteWorldSpotsAccess);
0688: }
0689:
0690: }
0691: catch (ClassNotFoundException classNotFoundException) {
0692: }
0693:
0694: objectOutputStream.flush();
0695: objectInputStream.close();
0696: objectOutputStream.close();
0697:
0698: socket.close();
0699:
0700: }
0701: catch (IOException iOException) {
0702: }
0703:
0704: }
0705:
0706: }
0707:
0708: public final HashSet getGates() {
0709:
0710: return this .gates;
0711:
0712: }
0713:
0714: //asynchronous addition while server running via a GUI side track tool
0715: public final void setGates(HashSet gates) {
0716:
0717: this .gates = gates;
0718:
0719: }
0720:
0721: //asynchronous addition while server running via a GUI side track tool
0722: public final void addGate(Gate gate) {
0723:
0724: this .gates.add(gate);
0725:
0726: }
0727:
0728: //asynchronous deletion while server running via a GUI side track tool
0729: public final void removeGate(Gate gate) {
0730:
0731: this .gates.remove(gate);
0732:
0733: }
0734:
0735: //Queries the Gates to be sure they still serve some Virtual Worlds
0736: //queries servers and delete unreachable servers
0737: //be cautious before using this method as servers may be only temporary unreachable
0738: public final void updateGates() {
0739:
0740: Socket socket;
0741: ObjectOutputStream objectOutputStream;
0742: ObjectInputStream objectInputStream;
0743:
0744: ControlRequest controlRequest;
0745: ControlReply controlReply;
0746: Gate gate;
0747: Iterator iterator;
0748:
0749: iterator = this .getGates().iterator();
0750: while (iterator.hasNext()) {
0751: //query distant server and fetch informations
0752: //distant server should send information to update
0753: gate = (Gate)iterator.next();
0754:
0755: try {
0756:
0757: //query distant server and fetch informations
0758: socket = new Socket(this .getIP(), this .getPort(), gate.getIP(), gate.getPort());
0759:
0760: objectInputStream = new ObjectInputStream(socket.getInputStream());
0761: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
0762:
0763: controlRequest = new ControlRequest(ControlRequest.INFORMATION);
0764: // send request
0765: objectOutputStream.writeObject(controlRequest);
0766:
0767: // read response
0768: try {
0769:
0770: controlReply = (ControlReply) objectInputStream.readObject();
0771:
0772: if (controlReply.getReplyKind()!=ControlReply.REFUSED) {
0773:
0774: this .removeGate(gate);
0775: }
0776:
0777: }
0778: catch (ClassNotFoundException classNotFoundException) {
0779: }
0780:
0781: objectOutputStream.flush();
0782: objectInputStream.close();
0783: objectOutputStream.close();
0784:
0785: socket.close();
0786:
0787: }
0788: catch (IOException iOexception) {
0789: }
0790:
0791: }
0792:
0793: }
0794:
0795: //send control request
0796: private void sendControlRequest(Gate gate, ControlRequest controlRequest) {
0797:
0798: Socket socket;
0799: ObjectOutputStream objectOutputStream;
0800:
0801: try {
0802:
0803: socket = new Socket(this .getIP(), this .getPort(), gate.getIP(), gate.getPort());
0804:
0805: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
0806:
0807: // send request
0808: objectOutputStream.writeObject(controlRequest);
0809:
0810: objectOutputStream.flush();
0811: objectOutputStream.close();
0812:
0813: socket.close();
0814:
0815: }
0816: catch (IOException iOexception) {
0817: }
0818:
0819: }
0820:
0821: private void waitControlRequest(Gate gate, ControlRequest controlRequest) {
0822:
0823: Socket socket;
0824: ObjectInputStream objectInputStream;
0825: ControlReply controlReply;
0826:
0827: try {
0828:
0829: //query distant server and fetch informations
0830: socket = new Socket(this .getIP(), this .getPort(), gate.getIP(), gate.getPort());
0831:
0832: objectInputStream = new ObjectInputStream(socket.getInputStream());
0833:
0834: // read response
0835: try {
0836: controlReply = (ControlReply) objectInputStream.readObject();
0837: }
0838: catch (ClassNotFoundException classNotFoundException) {
0839: }
0840:
0841: objectInputStream.close();
0842:
0843: socket.close();
0844:
0845: }
0846: catch (IOException iOexception) {
0847: }
0848:
0849: }
0850:
0851: //work control request
0852: private ControlReply workOutControlRequest(ControlRequest controlRequest) {
0853:
0854: ControlReply controlReply;
0855:
0856: controlReply = new ControlReply(ControlReply.ACCEPTED);
0857:
0858: if (controlRequest.getAccessKind()==ControlRequest.INFORMATION) {
0859: controlReply.setObjectValue(this .getInformation());
0860: } else {
0861: if (controlRequest.getAccessKind()==ControlRequest.LOCALWORLDSPOTS) {
0862: controlReply.setObjectValue(this .getLocalWorldSpots());
0863: } else {
0864: if (controlRequest.getAccessKind()==ControlRequest.REMOTEWORLDSPOTS) {
0865: controlReply.setObjectValue(this .getRemoteServers());
0866: } else {
0867: if (controlRequest.getAccessKind()==ControlRequest.GATES) {
0868: controlReply.setObjectValue(this .getGates());
0869: } else {
0870: //(controlRequest.getAccessKind()==ControlRequest.TIME)
0871: controlReply.setObjectValue(new Long(this .getServerTime()));
0872: }
0873: }
0874: }
0875: }
0876:
0877: return controlReply;
0878:
0879: }
0880:
0881: //socket should be an active socket from which the notification was received
0882: private void workOutControlNotification(Socket socket, ControlNotification controlNotification) {
0883:
0884: Gate gate;
0885: ControlRequest controlRequest;
0886:
0887: //use socket parameters
0888: gate = new Gate(socket.getInetAddress(), socket.getPort());
0889:
0890: if (controlNotification.getNotifyKind()==ControlNotification.LOCALWORLDSPOTS) {
0891: //retrieve IP of server to send a ControlRequest
0892: controlRequest = new ControlRequest(ControlRequest.LOCALWORLDSPOTS);
0893: this .sendControlRequest(gate, controlRequest);
0894: } else {
0895: //(controlNotification.getNotifyKind()==ControlNotification.ENDOFSERVICE)
0896: this .removeGate(gate);
0897: }
0898:
0899: }
0900:
0901: //send control reply
0902: private void sendControlReply(Gate gate, ControlReply controlReply) {
0903:
0904: Socket socket;
0905: ObjectOutputStream objectOutputStream;
0906:
0907: try {
0908:
0909: socket = new Socket(this .getIP(), this .getPort(), gate.getIP(), gate.getPort());
0910:
0911: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
0912:
0913: // send request
0914: objectOutputStream.writeObject(controlReply);
0915:
0916: objectOutputStream.flush();
0917: objectOutputStream.close();
0918:
0919: socket.close();
0920:
0921: }
0922: catch (IOException iOexception) {
0923: }
0924:
0925: }
0926:
0927: //read control reply
0928: private void workOutControlReply(ControlReply controlReply) {
0929:
0930: //YYYYYYYYYYYYYYYYYYY
0931: }
0932:
0933: //called automatically when reaching world spot boundary or from user request originating from WorldSpot
0934:
0935: //this actually sends the object or kicks out the Avatar (the Status of the Original avatar is set to Avatar.AWAY)
0936: //from one World Spot to another (may be not on the same Server)
0937: //position is the desired final position
0938: //Object (which must be ObjectWorld, BackgroundWorld or Avatar) may not arrive where you want (due to ruler's objection or may even fail)
0939: //if position is in the current World Spot, Object is just move according standard user rights
0940: //clientInformation is changed on the client side to smoothly operate transition in case you exported your avatar (emigration)
0941: public final void export(VirtualElement virtualElement, Transform3D position) {
0942:
0943: boolean found;
0944: WorldSpot worldSpot;
0945: RemoteWorldSpotsAccess remoteWorldSpotsAccess;
0946: Iterator iterator;
0947: Iterator iterator2;
0948: Avatar avatar;
0949: Vector3d vectorTransform;
0950: Bounds backGroundWorldBounds;
0951:
0952: if ((virtualElement!=null) && (position!=null)) {
0953:
0954: worldSpot = virtualElement.getWorldSpot(virtualElement.getUserOwner());
0955: //get object current worldSpot
0956: //verify position is outside of worldspot
0957: vectorTransform = new Vector3d();
0958: position.get(vectorTransform);
0959: if (!worldSpot.getBounds().intersect(new Point3d(vectorTransform))) {
0960: //verify there exist a worldspot with the receiving position
0961: iterator = this .getLocalWorldSpots().iterator();
0962: found = false;
0963: while (iterator.hasNext() && (!found)) {
0964: worldSpot = (WorldSpot)iterator.next();
0965: found = worldSpot.getBounds().intersect(new Point3d(vectorTransform));
0966: }
0967: if (found) {
0968: //if the worldspot is on the same server
0969: if (virtualElement instanceof ObjectWorld) {
0970: ((ObjectWorld)virtualElement).setTransform3D(position);
0971: }
0972: //YYYYYYYYYYYYYYYYYY
0973: } else {
0974: found = false;
0975: iterator = this .getRemoteServers().iterator();
0976: while (iterator.hasNext() && (!found)) {
0977: remoteWorldSpotsAccess = (RemoteWorldSpotsAccess) iterator.next();
0978: iterator2 = remoteWorldSpotsAccess.getRemoteWorldSpots(this ).iterator();
0979: while (iterator.hasNext() && (!found)) {
0980: worldSpot = (WorldSpot)iterator.next();
0981: found = worldSpot.getBounds().intersect(new Point3d(vectorTransform));
0982: }
0983: }
0984: if (found) {
0985: //if the worldspot is on a different server
0986: //contact the server and ask if it can instanciate an object with the same features and delete this virtualElement
0987: //create an avatar that mimics current avatar to provide an owner and a receiver for the account if tourism occurs
0988: //YYYYYYYYYYYYYYYYY
0989: if (!worldSpot.getRuler().checkLoginAndPasswordExists(virtualElement.getUserOwner().getLoginInformation())) {
0990: //else the account already exists
0991: //YYYYYYYYYYYYYYYYY
0992: avatar = Avatar.createUserAccount(virtualElement.getUserOwner().getLoginInformation(), worldSpot.getRuler());
0993: //YYYY home position may be not on the same worldSpot
0994: worldSpot.instanciateSkinFromLibrary(virtualElement.getUserOwner().getSkin().getClass(), avatar, avatar.getHomePosition());
0995: } else {
0996: avatar = worldSpot.getRuler().findAvatar(virtualElement.getUserOwner().getLoginInformation());
0997: }
0998: if (virtualElement instanceof ObjectWorld) {
0999: if (virtualElement instanceof Skin) {
1000: worldSpot.instanciateSkinFromLibrary(((Skin)virtualElement).getClass(), avatar, position);
1001: } else {
1002: worldSpot.instanciateObjectWorldFromLibrary(((ObjectWorld)virtualElement).getClass(), avatar, position);
1003: }
1004: } else {
1005: if (virtualElement instanceof BackgroundWorld) {
1006: backGroundWorldBounds = ((BackgroundWorld)virtualElement).getBounds();
1007: backGroundWorldBounds.transform(position);
1008: worldSpot.instanciateBackgroundWorldFromLibrary(((BackgroundWorld)virtualElement).getClass(), avatar, backGroundWorldBounds);
1009: }
1010: }
1011: virtualElement.deleteVirtualElement(virtualElement.getUserOwner(), virtualElement);
1012: } else {
1013: //don't export because position is invalid
1014: }
1015: }
1016: }
1017:
1018: }
1019:
1020: }
1021:
1022: //same as export but between virtual worlds
1023: //position is the desired final position (it may not exist and the Object should be transfered in the World Spot near Transform3D.ZERO)
1024: public final void export(VirtualElement virtualElement, Gate gate, Transform3D position) {
1025:
1026: Avatar avatar;
1027: WorldSpot worldSpot;
1028: Bounds backGroundWorldBounds;
1029:
1030: if ((virtualElement!=null) && (position!=null) && (gate!=null)) {
1031:
1032: //object may be lost in the transfert
1033: //contact the server and ask if it can instanciate an object with the same features and delete this virtualElement
1034: //YYYYYYYY XXXXXXXXX
1035: //worldSpot = ;
1036: //create an avatar that mimics current avatar to provide an owner and a receiver for the account if tourism occurs
1037: //YYYYYYYYYYYYYYYYY
1038: if (!worldSpot.getRuler().checkLoginAndPasswordExists((virtualElement.getUserOwner().getLoginInformation()))) {
1039: //else the account already exists
1040: //YYYYYYYYYYYYYYYYY
1041: avatar = Avatar.createUserAccount(virtualElement.getUserOwner().getLoginInformation(), worldSpot.getRuler());
1042: worldSpot.instanciateSkinFromLibrary(virtualElement.getUserOwner().getSkin().getClass(), avatar, avatar.getHomePosition());
1043: }
1044: else {
1045: avatar = worldSpot.getRuler().findAvatar(virtualElement.getUserOwner().getLoginInformation());
1046: }
1047: if (virtualElement instanceof ObjectWorld) {
1048: if (virtualElement instanceof Skin) {
1049: worldSpot.instanciateSkinFromLibrary(((Skin)virtualElement).getClass(), avatar, position);
1050: } else {
1051: worldSpot.instanciateObjectWorldFromLibrary(((ObjectWorld)virtualElement).getClass(), avatar, position);
1052: }
1053: } else {
1054: if (virtualElement instanceof BackgroundWorld) {
1055: backGroundWorldBounds = ((BackgroundWorld)virtualElement).getBounds();
1056: backGroundWorldBounds.transform(position);
1057: worldSpot.instanciateBackgroundWorldFromLibrary(((ObjectWorld)virtualElement).getClass(), avatar, backGroundWorldBounds);
1058: }
1059: }
1060: //YYYYYYYYYYYYYYYYY
1061: virtualElement.deleteVirtualElement(virtualElement);
1062: }
1063: }
1064:
1065: //good to use when a World Spot is about to be closed
1066: //transfer users to another World Spot with pawns and belongings
1067: //Objects are transfered to new Lands if they can as usual
1068: //in fact everything happens just like if translated from original worldSpot location (relative to its center) to position
1069: //thus transferContents(sourceWorldSpot, new BoundingSphere(sourceWorldSpot.getBounds()).getCenter()) is a null operation
1070: //multiple worldSpots may own the resulting objects
1071: //tip: make a phone call to the destination ruler and warn him that something is going to happen
1072: //transfer between servers
1073: //basically copies the current world spot to a remote server and deletes it from the local server
1074: //theorically it should be smooth and safe for users but because it is not really possible to make a snapshot
1075: //of a world and changing every client connection rapidly there should be some delays at least
1076: //this command will probably generate a mess on the destination world
1077: //much of what was in the original world including relative position of objects may be lost in the transfer
1078: public final void transferContents(WorldSpot sourceWorldSpot, Transform3D position) {
1079:
1080: Transaction transaction;
1081: Extent extent;
1082: Query query;
1083: String filter;
1084: Collection collection;
1085: Iterator iterator;
1086: VirtualElement virtualElement;
1087: Transform3D offset;
1088: Point3d point3d;
1089: Transform3D transformPoint3d;
1090:
1091: if ((sourceWorldSpot!=null) && (position!=null)) {
1092:
1093: try {
1094: transaction = this .getPersistenceManager().currentTransaction();
1095: transaction.begin();
1096:
1097: extent = this .getPersistenceManager().getExtent(VirtualElement.class, true);
1098: filter = new String("SELECT * FROM VirtualElement");
1099: query = this .getPersistenceManager().newQuery(VirtualElement.class, extent, filter);
1100: collection = (Collection) query.execute();
1101:
1102: transaction.commit();
1103: }
1104: catch (Exception exception) {
1105: }
1106:
1107: point3d = new BoundingSphere(sourceWorldSpot.getBounds()).getCenter();
1108: transformPoint3d = new Transform3D();
1109: offset = new Transform3D(position);
1110: transformPoint3d.set(new Vector3d(point3d.x, point3d.y, point3d.z));
1111: offset.sub(transformPoint3d);
1112:
1113: iterator = collection.iterator();
1114:
1115: while (iterator.hasNext()) {
1116: virtualElement = (VirtualElement) iterator.next();
1117: if (virtualElement instanceof ObjectWorld) {
1118: this .export(virtualElement, ((ObjectWorld)virtualElement).getTransform3D().add(offset));
1119: } else {
1120: this .export(virtualElement, position);
1121: }
1122: }
1123:
1124: }
1125:
1126:
1127: //YYYYYYYY XXXXX
1128: //check bounds are big enough to receive the worldSpot
1129: //create accounts
1130: //rebuild filters, blockers, pass, tickets, home position, capabilities and policies
1131: //reconnect to pools
1132: //build remaing lands
1133: //populate libraries
1134: //instanciate objects
1135: //reconnect every client to new worldSpot
1136: //delete old worldspot
1137:
1138: }
1139:
1140: //same as transfer but between virtual worlds
1141: //position "describes" the world spot of destination
1142: //this command will probably generate a mess on the destination world
1143: //much of what was in the original world including relative position of objects may be lost in the transfer
1144: public final void transferContents(WorldSpot worldSpot, Gate gate, Transform3D position) {
1145:
1146: Transaction transaction;
1147: Extent extent;
1148: Query query;
1149: String filter;
1150: Collection collection;
1151: Iterator iterator;
1152: VirtualElement virtualElement;
1153: Transform3D offset;
1154: Transform3D result;
1155: Point3d point3d;
1156:
1157: if ((worldSpot!=null) && (gate!=null) && (position!=null)) {
1158:
1159: try {
1160: transaction = this .getPersistenceManager().currentTransaction();
1161: transaction.begin();
1162:
1163: extent = this .getPersistenceManager().getExtent(VirtualElement.class, true);
1164: filter = new String("SELECT * FROM VirtualElement");
1165: query = this .getPersistenceManager().newQuery(VirtualElement.class, extent, filter);
1166: collection = (Collection) query.execute();
1167:
1168: transaction.commit();
1169:
1170: point3d = new Point3d();
1171: new BoundingSphere(worldSpot.getBounds()).getCenter(point3d);
1172: offset = new Transform3D();
1173: offset.set(new Vector3d(point3d.x, point3d.y, point3d.z));
1174: result = new Transform3D(position);
1175: result.sub(offset);
1176:
1177: iterator = collection.iterator();
1178:
1179: while (iterator.hasNext()) {
1180: virtualElement = (VirtualElement) iterator.next();
1181: if (virtualElement instanceof ObjectWorld) {
1182: offset = new Transform3D(((ObjectWorld)virtualElement).getTransform3D());
1183: offset.add(result);
1184: this .export(virtualElement, gate, offset);
1185: } else {
1186: this .export(virtualElement, gate, position);
1187: }
1188: }
1189:
1190: }
1191: catch (Exception exception) {
1192: }
1193:
1194: }
1195:
1196: //YYYYYYYY XXXXX
1197:
1198: }
1199:
1200: //closes all active connections in the given LOCAL world spot
1201: //avatars are therefore all Avatar.AWAY
1202: public final void evict(WorldSpot worldSpot) {
1203:
1204: Collection avatars;
1205: Iterator iterator;
1206: Avatar avatar;
1207:
1208: if ((worldSpot!=null) && (this .getLocalWorldSpots().contains(worldSpot))) {
1209:
1210: avatars = worldSpot.getAvatars(worldSpot.getRuler());
1211:
1212: iterator = avatars.iterator();
1213: while (iterator.hasNext()) {
1214: avatar = (Avatar) iterator.next();
1215: this .closeConnection(avatar);
1216: }
1217:
1218: }
1219:
1220: }
1221:
1222: //when this Server is going to be closed, send a message to all remaining users
1223: //and to all gates
1224: //date is the date after which the server is meant to be unreliable
1225: //asynchronous call while server running via a GUI side track tool
1226: public final void warnEndOfService(Date date) {
1227:
1228: Socket socket;
1229: ObjectOutputStream objectOutputStream;
1230:
1231: ControlNotification controlNotification;
1232: WorldSpot worldSpot;
1233: WorldSpotBasicInformation worldSpotBasicInformation;
1234: RemoteWorldSpotsAccess remoteWorldSpotsAccess;
1235: Gate gate;
1236: Iterator iterator;
1237:
1238: //send message to remaining users on local world spots
1239: iterator = this .getLocalWorldSpots().iterator();
1240: while (iterator.hasNext()) {
1241: worldSpot= (WorldSpot) iterator.next();
1242: worldSpotBasicInformation = new WorldSpotBasicInformation(worldSpot.getRuler(), worldSpot.getBounds(), worldSpot.getInformation());
1243: }
1244:
1245: //send message to remaining users of remote servers (distant world spots)
1246: iterator = this .getRemoteServers().iterator();
1247: while (iterator.hasNext()) {
1248: remoteWorldSpotsAccess = (RemoteWorldSpotsAccess)iterator.next();
1249:
1250: try {
1251:
1252: //query distant server and send information
1253: socket = new Socket(this .getIP(), this .getPort(), remoteWorldSpotsAccess.getIP(), remoteWorldSpotsAccess.getPort());
1254:
1255: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
1256:
1257: controlNotification = new ControlNotification(ControlNotification.ENDOFSERVICE, date);
1258: // send request
1259: objectOutputStream.writeObject(controlNotification);
1260:
1261: // read response
1262: objectOutputStream.flush();
1263: objectOutputStream.close();
1264:
1265: socket.close();
1266:
1267: }
1268: catch (IOException iOexception) {
1269: }
1270: }
1271:
1272: //send message to gates
1273: iterator = this .getGates().iterator();
1274: while (iterator.hasNext()) {
1275: gate = (Gate)iterator.next();
1276:
1277: try {
1278: //query distant server and send information
1279: socket = new Socket(this .getIP(), this .getPort(), gate.getIP(), gate.getPort());
1280: objectOutputStream = new ObjectOutputStream(socket.getOutputStream());
1281:
1282: controlNotification = new ControlNotification(ControlNotification.ENDOFSERVICE, date);
1283: // send request
1284: objectOutputStream.writeObject(controlNotification);
1285:
1286: // read response
1287: objectOutputStream.flush();
1288: objectOutputStream.close();
1289:
1290: socket.close();
1291:
1292: } catch (IOException iOException) {
1293: }
1294:
1295: }
1296:
1297: }
1298:
1299: //does a warn and closes everything smoothly
1300: public final void doEndOfService() {
1301:
1302: HashSet worldSpots;
1303: Iterator iterator;
1304: WorldSpot worldSpot;
1305:
1306: this .warnEndOfService(new Date(System.currentTimeMillis()));
1307: worldSpots = this .getLocalWorldSpots();
1308: iterator = worldSpots.iterator();
1309: while(iterator.hasNext()) {
1310: worldSpot = (WorldSpot) iterator.next();
1311: this .evict(worldSpot);
1312: }
1313:
1314: }
1315:
1316: //asynchronous call while server running via a GUI side track tool
1317: //automatically manages Gates by using a ServerHelper
1318: //calls to addGates and setGates are made
1319: //useful to add gates to ease travel use of your users between virtual worlds
1320: public void queryServerHelper(InetAddress IP, int port) {
1321:
1322: ServerHelper serverHelper;
1323: HashSet hashSet;
1324: Gate gate;
1325:
1326: serverHelper = new ServerHelper(this .getIP(), this .getPort());
1327: gate = new Gate(IP, port);
1328: hashSet = serverHelper.getGates(gate);
1329: hashSet.addAll(this .getGates());
1330: this .setGates(hashSet);
1331:
1332: }
1333:
1334: //asynchronous call while server running via a GUI side track tool
1335: //automatically manages Gates by using a ServerHelper
1336: //calls to addGates and setGates are made
1337: //useful to add gates to ease travel use of your users between virtual worlds
1338: //uses a wellKnownServer
1339: public void queryServerHelper() {
1340:
1341: ServerHelper serverHelper;
1342: HashSet hashSet;
1343:
1344: serverHelper = new ServerHelper(this .getIP(), this .getPort());
1345: hashSet = serverHelper.getGates(serverHelper.getWellKnownServer());
1346: hashSet.addAll(this .getGates());
1347: this .setGates(hashSet);
1348:
1349: }
1350:
1351: public long getServerTime() {
1352:
1353: return System.currentTimeMillis() + offset;
1354:
1355: }
1356:
1357: //asynchronous addition while server running via a GUI side track tool
1358: public void setServerTimeOffset(long offset) {
1359:
1360: this .offset = offset;
1361:
1362: }
1363:
1364: //starts the server threads
1365: public void start() {
1366:
1367: }
1368:
1369: //stops the server
1370: public void stop() {
1371:
1372: try {
1373: this .getPersistenceManager().close();
1374: // this is done so that database can shut down properly
1375: //YYYYYYYYYYYYYYYYYY
1376: //fOStorePMF.close();
1377: }
1378: catch (Exception exception) {
1379: }
1380:
1381: //close network
1382: try {
1383:
1384: serverSocket.close();
1385:
1386: } catch (IOException iOException) {
1387: }
1388:
1389: }
1390:
1391: //sort of duplicate method with Avatar but the Avatar method can only be called when there is at least an avatar
1392: //behavior and parameters should roughly be the same
1393: public Avatar createRuler(LoginInformation loginInformation) {
1394:
1395: Avatar ruler;
1396: Transaction transaction;
1397:
1398: ruler = new Avatar(this , loginInformation);
1399:
1400: //ruler is allocated full worldSpot Land at worldSpot instanciation
1401: try {
1402:
1403: transaction = this .getPersistenceManager().currentTransaction();
1404: transaction.begin();
1405:
1406: this .getPersistenceManager().makePersistent(ruler);
1407:
1408: transaction.commit();
1409: }
1410: catch (Exception exception) {
1411: }
1412:
1413: return ruler;
1414:
1415: }
1416:
1417:
1418: //be sure to add a new thread when adding a new world spot
1419: //the thread should implement the double cache system database-clients
1420: //and ensure proper slicing of tools and guides behaviors
1421:
1422: //The "listen" thread that accepts a connection to the server.
1423: //running thread to receive and treat Client requests
1424:
1425: public void run() {
1426:
1427: Socket socket;
1428:
1429: Authentification authentification;
1430: ClientInformation clientInformation;
1431: Avatar avatar;
1432: int accessKind;
1433: ObjectOutputStream objectOutputStream;
1434: ObjectInputStream objectInputStream;
1435: InputStream inputStream;
1436: OutputStream outputStream;
1437: //GZIPOutputStream gZIPOutputStream;
1438: //GZIPInputStream gZIPInputStream;
1439: BufferedOutputStream bufferedOutputStream;
1440: BufferedInputStream bufferedInputStream;
1441:
1442: // accept a connection
1443: try {
1444: socket = serverSocket.accept();
1445: socket.setTcpNoDelay(true);
1446: } catch (IOException iOException) {
1447: System.out.println("Server died: " + iOException.getMessage());
1448: iOException.printStackTrace();
1449: return;
1450: }
1451:
1452: // create a new thread to accept the next connection
1453: this .newListener();
1454: //the other solution would be to start the client in a new thread and keep looping on this thread
1455:
1456: try {
1457: //gZIPOutputStream = GZIPOutputStream(socket.getOutputStream());
1458: //bufferedOutputStream = new BufferedOutputStream(gZIPOutputStream);
1459: bufferedOutputStream = new BufferedOutputStream(socket.getOutputStream());
1460: objectOutputStream = new ObjectOutputStream(bufferedOutputStream);
1461:
1462: //gZIPInputStream = GZIPInputStream(socket.getInputStream());
1463: //bufferedInputStream = new BufferedInputStream(gZIPInputStream);
1464: bufferedInputStream = new BufferedInputStream(socket.getInputStream());
1465: objectInputStream = new ObjectInputStream(bufferedInputStream);
1466:
1467: authentification = (Authentification) objectInputStream.readObject();
1468:
1469: clientInformation = new ClientInformation(authentification.getIP(), authentification.getPort(), new String(""), this .getIP(), this .getPort(), authentification.getLoginInformation(), new Transform3D());
1470: accessKind = authentification.getAccessKind();
1471:
1472: switch (accessKind) {
1473: //addition and connect for the first time immediately are an immigration
1474: //you can use this process either for full accounts or guest accounts
1475: case Authentification.IMMIGRATE: {
1476: this .addAccount(clientInformation);
1477: this .reconnect(clientInformation);
1478: }
1479: //only adds account but does not open a client connection, useful mainly for ruler to set up batch accounts
1480: case Authentification.ADDITION: {
1481: this .addAccount(clientInformation);
1482: }
1483: case Authentification.RECONNECT: {
1484: //reconnect is the normal way of login to your account
1485: this .reconnect(clientInformation);
1486: }
1487: case Authentification.CLOSE_SESSION: {
1488: //to manually close the connection
1489: //server should close connection by itself if client is lost (power failure, network failure...)
1490: avatar = this .getAvatar(clientInformation);
1491: if (avatar!=null) {
1492: avatar.disconnectUser();
1493: }
1494: this .closeConnection(clientInformation);
1495: }
1496: case Authentification.DELETION: {
1497: //Deletes account
1498: //Does note need to be logged on to delete the account
1499: //actually closes the the connection if connected
1500: avatar = this .getAvatar(clientInformation);
1501: if (avatar!=null) {
1502: avatar.setStatus(Avatar.PAWN);
1503: }
1504: this .closeConnection(clientInformation);
1505: }
1506: case Authentification.IMMEDIATE_DELETION: {
1507: //Deletes also all properties using Avatar.TRASH_ALL as succession policy
1508: //not very cool for those who stay
1509: avatar = this .getAvatar(clientInformation);
1510: if (avatar!=null) {
1511: avatar.setSuccessionPolicy(Avatar.TRASH_ALL,Avatar.TRASH_ALL,Avatar.TRASH_ALL);
1512: avatar.setStatus(Avatar.PAWN);
1513: }
1514: this .closeConnection(clientInformation);
1515: }
1516: }
1517:
1518: //YYYYYYYYYYYYYYYYYYYYYYYYyy
1519: //this.sleep(300);
1520:
1521: }
1522: catch (Exception exception) {
1523: }
1524:
1525: }
1526:
1527: /**
1528: * Create a new thread to listen.
1529: */
1530: private void newListener() {
1531:
1532: (new Thread(this )).start();
1533:
1534: }
1535:
1536: //may return null
1537: private Avatar getAvatar(ClientInformation clientInformation) {
1538:
1539: Transaction transaction;
1540: Extent extent;
1541: Query query;
1542: String filter;
1543: Collection collection;
1544:
1545: if (clientInformation!=null) {
1546: try {
1547: transaction = this .getPersistenceManager().currentTransaction();
1548: transaction.begin();
1549:
1550: extent = this .getPersistenceManager().getExtent(Avatar.class, true);
1551: filter = new String("SELECT Avatar FROM Avatar a WHERE a.getLoginInformation().checkLoginAndPassword(clientInformation.getLoginInformation())==true");
1552: query = this .getPersistenceManager().newQuery(Avatar.class, extent, filter);
1553: collection = (Collection) query.execute();
1554:
1555: transaction.commit();
1556:
1557: if (collection.size()!=0) {
1558: return (Avatar)(collection.iterator().next());
1559: }
1560: else {
1561: return null;
1562: }
1563:
1564: }
1565: catch (Exception exception) {
1566: return null;
1567: }
1568:
1569: }
1570: else {
1571: return null;
1572: }
1573:
1574: }
1575:
1576: // check if there is no active client for that account
1577: //don't open connection if so
1578: //reply cause of failure to user
1579: //YYYYYYYY XXXXXXX
1580: private void addAccount(ClientInformation clientInformation) {
1581:
1582: Avatar.createUserAccount(clientInformation.getLoginInformation());
1583: avatar.setStatus(Avatar.AWAY);
1584:
1585: }
1586:
1587: //return reply account not found or start as guest
1588: //YYYYYYYY XXXX
1589: private void reconnect(ClientInformation clientInformation) {
1590:
1591: if (status()!=Avatar.Pawn) {
1592: //YYYYYYYY XXXXX
1593: //check position is on this server and find worldspot else send a message to client containing the correct ip and port to access the server
1594: avatar.setStatus(Avatar.IMMIGRATE);
1595: avatar.setStatus(Avatar.NORMAL);
1596: //YYYYYYYY XXXX
1597: }
1598:
1599: }
1600:
1601: //YYYYYYYY XXXX
1602: public void closeConnection(Avatar avatar) {
1603: }
1604:
1605: //YYYYYYYY XXXX
1606: public void closeConnection(ClientInformation clientInformation) {
1607:
1608: try {
1609: objectOutputStream.flush();
1610: objectOutputStream.close();
1611: //gZIPOutputStream.flush();
1612: //gZIPOutputStream.finish();
1613: //gZIPOutputStream.close();
1614: bufferedOutputStream.flush();
1615: bufferedOutputStream.close();
1616:
1617: objectInputStream.close();
1618: //gZIPInputStream.close();
1619: bufferedInputStream.close();
1620:
1621: socket.close();
1622: } catch (IOException e) {
1623: }
1624:
1625: }
1626:
1627: //if no response from this client for some time close this serversocket and this thread
1628: private void autoCloseConnection(ClientInformation clientInformation) {
1629:
1630: this .closeConnection(clientInformation);
1631:
1632: }
1633:
1634: //server out cache
1635: private HashSet sendObjects;
1636:
1637: //when the client logs a special request is made to send everything and not just updated objects
1638: //client exists or a new account is created as direct child to the ruler
1639: //YYYYYYYY XXXX
1640: private HashSet workOutFirstRequest(ClientInformation clientInformation) {
1641:
1642: LoginInformation loginInformation;
1643: BoundingSphere boundingSphere;
1644: Transaction transaction;
1645: Extent extent;
1646: Query query;
1647: String filter;
1648: Collection collection;
1649: Avatar avatar;
1650: Iterator iterator;
1651: Point3d positionAsPoint;
1652: Vector3d positionAsVector;
1653: Collection simpleCollection;
1654: NetworkElement networkElement;
1655: HashSet resultCollection;
1656: Collection collection1;
1657: Collection collection2;
1658: boolean found;
1659: Iterator iterator2;
1660: Collection blockerCollection;
1661:
1662: loginInformation = clientInformation.getLoginInformation();
1663:
1664: try {
1665: transaction = this .getPersistentManager().currentTransaction();
1666: transaction.begin();
1667:
1668: extent = this .getPersistentManager().getExtent(Avatar.class, true);
1669: filter = new String("SELECT Avatar FROM Avatar a WHERE a.getLoginInformation().checkLoginAndPassword(loginInformation)==true");
1670: query = this .getPersistentManager().newQuery(Avatar.class, extent, filter);
1671: collection = (Collection) query.execute();
1672:
1673: transaction.commit();
1674: }
1675: catch (Exception exception) {
1676: }
1677:
1678: if (collection.size()==0) {
1679: //or start a new account
1680: avatar = Avatar.createUserAccount(loginInformation, this .getWorldSpot().getRuler());
1681: avatar.setStatus(Avatar.IMMIGRATING);
1682: avatar.setStatus(Avatar.NORMAL);
1683: } else {
1684: avatar = (Avatar) collection.iterator.next();
1685: avatar.setStatus(Avatar.NORMAL);
1686: }
1687:
1688: //start connection
1689:
1690: //try to set the avatar to the desired position
1691: if (avatar.getSkin()!=null) {
1692: avatar.getSkin().setTransform3D(clientInformation.getPosition());
1693: clientInformation.setPosition(avatar.getSkin().getTransform3D());
1694: }
1695:
1696: //use the client scope
1697: boundingSphere = new BoundingSphere(clientInformation.getPosition(), clientInformation.getDrawingRadius());
1698:
1699: //get land the avatar is on
1700: try {
1701: transaction = this .getPersistentManager().currentTransaction();
1702: transaction.begin();
1703:
1704: extent = this .getPersistentManager().getExtent(Filter.class, true);
1705: filter = new String("SELECT Land FROM Land l WHERE l.getBounds().intersects(boundingSphere)");
1706: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
1707: collection = (Collection) query.execute();
1708:
1709: transaction.commit();
1710: }
1711: catch (Exception exception) {
1712: }
1713:
1714: positionAsVector = new Vector3d();
1715: clientInformation.getPosition().get(positionAsVector);
1716: positionAsPoint = new Point3d(positionAsVector);
1717: found = false;
1718: iterator = collection.iterator();
1719: while (iterator.hasNext() && (!found)) {
1720: land = (Land)iterator.next();
1721: found = land.getBounds().intersect(positionAsPoint);
1722: }
1723:
1724: simpleCollection = new Collection(collection);
1725:
1726: //whether in his home or on someone's land, this land should be navigable for that user because of the previous setTransform
1727: if (found) {
1728: land.doEnter(avatar);
1729: simpleCollection.remove(land);
1730: }
1731:
1732: iterator = simpleCollection.iterator();
1733: while (iterator.hasNext()) {
1734: ((Land)iterator.next()).doLook(avatar);
1735: }
1736:
1737: //get and display stuff depending on land capabilities
1738:
1739: //select matching BackgroundWorlds from bounds and capabilities
1740: try {
1741: transaction = this .getPersistentManager().currentTransaction();
1742: transaction.begin();
1743:
1744: extent = this .getPersistentManager().getExtent(Filter.class, true);
1745: filter = new String("SELECT BackgroundWorld FROM BackgroundWorld b WHERE b.getGeometryBounds().intersects(boundingSphere)");
1746: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
1747: collection1 = (Collection) query.execute();
1748:
1749: transaction.commit();
1750: }
1751: catch (Exception exception) {
1752: }
1753:
1754: //select matching ObjectWorlds from bounds and capabilities
1755: try {
1756: transaction = this .getPersistentManager().currentTransaction();
1757: transaction.begin();
1758:
1759: extent = this .getPersistentManager().getExtent(Filter.class, true);
1760: filter = new String("SELECT ObjectWorld FROM ObjectWorld o WHERE o.getGeometryBounds().intersects(boundingSphere)");
1761: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
1762: collection2 = (Collection) query.execute();
1763:
1764: transaction.commit();
1765: }
1766: catch (Exception exception) {
1767: }
1768:
1769: collection = this .filterCollection(avatar, collection1.addAll(collection2));
1770:
1771: //find blockers
1772: try {
1773: transaction = this .getPersistentManager().currentTransaction();
1774: transaction.begin();
1775:
1776: extent = this .getPersistentManager().getExtent(Filter.class, true);
1777: filter = new String("SELECT Blocker FROM Blocker b WHERE b.getRequester()==avatar");
1778: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
1779: blockerCollection = (Collection) query.execute();
1780:
1781: transaction.commit();
1782: }
1783: catch (Exception exception) {
1784: }
1785:
1786: //don't send blockers
1787:
1788: iterator = collection.iterator();
1789: resultCollection = new HashSet();
1790: while (iterator.hasNext()) {
1791: virtualElement = (VirtualElement) iterator.next();
1792:
1793: virtualElement.doVisible();
1794: virtualElement.doSonore();
1795:
1796: //dispatch notifications to clients with filters on each object
1797: try {
1798: transaction = this .getPersistentManager().currentTransaction();
1799: transaction.begin();
1800:
1801: extent = this .getPersistentManager().getExtent(Filter.class, true);
1802: filter = new String("SELECT Filter FROM Filter f WHERE f.getObject()==virtualElement");
1803: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
1804: filterCollection = (Collection) query.execute();
1805:
1806: transaction.commit();
1807: }
1808: catch (Exception exception) {
1809: }
1810:
1811: iterator2 = filterCollection.iterator();
1812: while (iterator2.hasNext()) {
1813: filter = (Filter) iterator2.next();
1814: if ((filter.getAccessKind() == Filter.READ_ACCESS) || (filter.getAccessKind() == Filter.READ_WRITE_ACCESS)) {
1815: this .sendNotification(filter.getRequester(), virtualElement);
1816: }
1817: }
1818:
1819: //don't send elements with a blocker
1820: found = false;
1821: iterator2 = blockerCollection.iterator();
1822: while (iterator2.hasNext() && (!found)) {
1823: found = ((((Blocker)iterator2.next()).getObject()) == virtualElement);
1824: }
1825: if (!found) {
1826:
1827: //initiate transfer
1828: if (virtualElement instanceof BackgroundWorld) {
1829: virtualElement.getBackgroundDescription().setApplicationBounds(virtualElement.getBounds());
1830: networkElement = new NetworkElement(NetworkElement.NOT_REQUESTED, new Transform3D(), virtualElement.getBackgroundDescription(), virtualElement.getSoundDescription(), virtualElement.getStatus());
1831: } else {
1832: //if virtualElement instanceof ObjectWorld
1833: networkElement = new NetworkElement(NetworkElement.NOT_REQUESTED, virtualElement.getTransform3D(), virtualElement.getGeometryDescription(), virtualElement.getSoundDescription(), virtualElement.getStatus());
1834: }
1835: networkElement.setInformation(virtualElement.getInformation());
1836: networkElement.setPrice(virtualElement.getPrice());
1837: networkElement.setCurrency(virtualElement.getCurrency());
1838: networkElement.setOthersAccessRights(Avatar.PEERLORD, virtualElement.getOthersAccessRights(Avatar.PEERLORD));
1839: networkElement.setOthersAccessRights(Avatar.PEER, virtualElement.getOthersAccessRights(Avatar.PEER));
1840: networkElement.setOthersAccessRights(Avatar.PEERVASSAL, virtualElement.getOthersAccessRights(Avatar.PEERVASSAL));
1841: networkElement.setOthersAccessRights(Avatar.VASSAL, virtualElement.getOthersAccessRights(Avatar.VASSAL));
1842: networkElement.setDesignerCapabilities(virtualElement.getDesignerCapabilities());
1843:
1844: resultCollection.add(networkElement);
1845:
1846: }
1847:
1848: }
1849:
1850: //keep a reference to objects send
1851: objectsSend = resultCollection;
1852:
1853: //send to network
1854: return resultCollection;
1855:
1856:
1857: }
1858:
1859: //send a notification to a client if a filter is matching
1860: private NetworkElement sendNotification(Avatar avatar, VirtualElement virtualElement) {
1861:
1862: //YYYYYYYYYYYYYYYYYY
1863: if (avatar.getStatus()==Avatar.NORMAL) {
1864:
1865: if (virtualElement instanceof BackgroundWorld) {
1866: virtualElement.getBackgroundDescription().setApplicationBounds(virtualElement.getBounds());
1867: networkElement = new NetworkElement(NetworkElement.NOT_REQUESTED, new Transform3D(), virtualElement.getBackgroundDescription(), virtualElement.getSoundDescription(), virtualElement.getStatus(), virtualElement.hashCode());
1868: } else {
1869: //if virtualElement instanceof ObjectWorld
1870: networkElement = new NetworkElement(NetworkElement.NOT_REQUESTED, virtualElement.getTransform3D(), virtualElement.getGeometryDescription(), virtualElement.getSoundDescription(), virtualElement.getStatus(), virtualElement.hashCode());
1871: }
1872: networkElement.setInformation(virtualElement.getInformation());
1873: networkElement.setPrice(virtualElement.getPrice());
1874: networkElement.setCurrency(virtualElement.getCurrency());
1875: networkElement.setOthersAccessRights(Avatar.PEERLORD, virtualElement.getOthersAccessRights(Avatar.PEERLORD));
1876: networkElement.setOthersAccessRights(Avatar.PEER, virtualElement.getOthersAccessRights(Avatar.PEER));
1877: networkElement.setOthersAccessRights(Avatar.PEERVASSAL, virtualElement.getOthersAccessRights(Avatar.PEERVASSAL));
1878: networkElement.setOthersAccessRights(Avatar.VASSAL, virtualElement.getOthersAccessRights(Avatar.VASSAL));
1879: networkElement.setDesignerCapabilities(virtualElement.getDesignerCapabilities());
1880:
1881: return networkElement;
1882:
1883: } else {
1884: return null;
1885: }
1886:
1887: }
1888:
1889: //send appearing class
1890: public NetworkElement sendAdditionNotification(Avatar avatar, Object virtualElement) {
1891:
1892: //YYYYYYYYYYYYYYYYYY
1893: return new NetworkElement(0, new Transform3D(), new Shape3D(), new PointSound(), new Object(), 0);
1894:
1895: }
1896:
1897: //sends a notification about disappearing objects
1898: public NetworkElement sendDeletionNotification(Avatar avatar, int oldReference) {
1899:
1900: if (avatar.getStatus()==Avatar.NORMAL) {
1901:
1902: networkElement = new NetworkElement(NetworkElement.NOT_REQUESTED, null, null, null, null, oldReference);
1903: networkElement.setInformation(null);
1904: networkElement.setPrice(null);
1905: networkElement.setCurrency(null);
1906: networkElement.setOthersAccessRights(Avatar.PEERLORD, VirtualElement.HIDDEN);
1907: networkElement.setOthersAccessRights(Avatar.PEER, VirtualElement.HIDDEN);
1908: networkElement.setOthersAccessRights(Avatar.PEERVASSAL, VirtualElement.HIDDEN);
1909: networkElement.setOthersAccessRights(Avatar.VASSAL, VirtualElement.HIDDEN);
1910: networkElement.setDesignerCapabilities(VirtualElement.NO_CAPABILITY);
1911:
1912: return networkElement;
1913:
1914: } else {
1915: return null;
1916: }
1917:
1918: }
1919:
1920: //we actually don't send every field especially user and designer rights, information, price and currency
1921: //requestId and status are managed on a different level
1922: private void sendNetworkElements(HashSet elements) {
1923:
1924: BranchGroup branchGroup;
1925: SceneGraphStreamWriter sceneGraphStreamWriter;
1926: Iterator iterator;
1927: NetworkElement networkElement;
1928: HashMap namedObjects;
1929:
1930: sceneGraphStreamWriter = new SceneGraphStreamWriter(objectOutputStream);
1931: namedObjects = new HashMap();
1932: branchGroup = new BranchGroup();
1933:
1934: while (iterator.hasNext()) {
1935: networkElement = (NetworkElement) iterator.next();
1936: transformGroup = new TransformGroup(networkElement.getTransform3D());
1937: transformGroup.setUserData(networkElement.getReference());
1938: transformGroup.addChild(networkElement.getGeometryDescription());
1939: transformGroup.addChild(networkElement.getSoundDescription());
1940: branchGroup.addChild(transformGroup);
1941: }
1942:
1943: sceneGraphStreamWriter.writeBranchGraph(branchGroup, namedObjects);
1944: sceneGraphStreamWriter.close();
1945:
1946: }
1947:
1948: //work out standard request to update objects
1949: private void workOutRequest(NetworkElement networkElement) {
1950:
1951: Transaction transaction;
1952: Extent extent;
1953: Query query;
1954: String filter;
1955: Collection collection;
1956: long requestID;
1957:
1958: //keep requestID to send replies
1959: requestID = networkElement.getRequestID();
1960:
1961: //react to objects received from client
1962: try {
1963: transaction = this .getPersistentManager().currentTransaction();
1964: transaction.begin();
1965:
1966: extent = this .getPersistentManager().getExtent(Avatar.class, true);
1967: filter = new String("SELECT VirtualElement FROM VirtualElement v WHERE v.hashCode()==networkElement.getObjectReference()");
1968: query = this .getPersistentManager().newQuery(Avatar.class, extent, filter);
1969: collection = (Collection) query.execute();
1970:
1971: transaction.commit();
1972: }
1973: catch (Exception exception) {
1974: }
1975:
1976: collection = this .filterCollection(collection);
1977: if (collection.size()!=0) {
1978: //just take the first one that is writable by the user
1979: virtualElement = (VirtualElement) iterator.next();
1980: //hashCode should be unique but who knows ?
1981: //XXXXXX
1982: //we reuse every non null field send by the user
1983: if (networkElement.getTransform3D()!=null) {
1984: virtualElement.setTransform3D(networkElement.getTransform3D());
1985: }
1986: if (networkElement.getGeometryDescription()!=null) {
1987: virtualElement.setGeometryDescription(networkElement.getGeometryDescription());
1988: }
1989: if (networkElement.getSoundDescription()!=null) {
1990: virtualElement.setSoundDescription(networkElement.getSoundDescription());
1991: }
1992: if (networkElement.getStatus()!=null) {
1993: virtualElement.setStatus(networkElement.getStatus());
1994: }
1995: }
1996: //else {
1997: //object has been deleted or reference is corrupted
1998: //get rid of this message
1999: //}
2000:
2001: //try to set the avatar to the desired position
2002: if (avatar.getSkin()!=null) {
2003: avatar.getSkin().setTransform3D(clientInformation.getPosition());
2004: clientInformation.setPosition(avatar.getSkin().getTransform3D());
2005: }
2006:
2007: //use the client scope
2008: boundingSphere = new BoundingSphere(clientInformation.getPosition(), clientInformation.getDrawingRadius());
2009:
2010: //get land the avatar is on
2011: try {
2012: transaction = this .getPersistentManager().currentTransaction();
2013: transaction.begin();
2014:
2015: extent = this .getPersistentManager().getExtent(Filter.class, true);
2016: filter = new String("SELECT Land FROM Land l WHERE l.getBounds().intersects(boundingSphere)");
2017: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2018: collection = (Collection) query.execute();
2019:
2020: transaction.commit();
2021: }
2022: catch (Exception exception) {
2023: }
2024:
2025: positionAsPoint = new Point3d();
2026: position.get(positionAsPoint);
2027: found = false;
2028: iterator = collection.iterator();
2029: while (iterator.hasNext() && (!found)) {
2030: found = ((Land)iterator.next()).getBounds().intersect(positionAsPoint);
2031: }
2032:
2033: //whether in his home or on someone's land, this land should be navigable for that user because of the previous setTransform
2034: land.doEnter(avatar);
2035:
2036: simpleCollection = new Collection(collection);
2037: simpleCollection.remove(land);
2038: iterator = simpleCollection.iterator();
2039: while (iterator.hasNext()) {
2040: ((Land)iterator.next()).doLook(avatar);
2041: }
2042:
2043: //get and display stuff depending on land capabilities
2044:
2045: //select matching BackgroundWorlds from bounds and capabilities
2046: try {
2047: transaction = this .getPersistentManager().currentTransaction();
2048: transaction.begin();
2049:
2050: extent = this .getPersistentManager().getExtent(Filter.class, true);
2051: filter = new String("SELECT BackgroundWorld FROM BackgroundWorld b WHERE b.getGeometryBounds().intersects(boundingSphere)");
2052: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2053: collection1 = (Collection) query.execute();
2054:
2055: transaction.commit();
2056: }
2057: catch (Exception exception) {
2058: }
2059:
2060: //select matching ObjectWorlds from bounds and capabilities
2061: try {
2062: transaction = this .getPersistentManager().currentTransaction();
2063: transaction.begin();
2064:
2065: extent = this .getPersistentManager().getExtent(Filter.class, true);
2066: filter = new String("SELECT ObjectWorld FROM ObjectWorld o WHERE o.getGeometryBounds().intersects(boundingSphere)");
2067: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2068: collection2 = (Collection) query.execute();
2069:
2070: transaction.commit();
2071: }
2072: catch (Exception exception) {
2073: }
2074:
2075: collection = this .filterCollection(avatar, collection1.addAll(collection2));
2076:
2077: //find blockers
2078: try {
2079: transaction = this .getPersistentManager().currentTransaction();
2080: transaction.begin();
2081:
2082: extent = this .getPersistentManager().getExtent(Filter.class, true);
2083: filter = new String("SELECT Blocker FROM Blocker b WHERE b.getRequester()==avatar");
2084: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2085: blockerCollection = (Collection) query.execute();
2086:
2087: transaction.commit();
2088: }
2089: catch (Exception exception) {
2090: }
2091:
2092: //don't send blockers
2093:
2094: iterator = collection.iterator();
2095: resultCollection = new HashSet();
2096: while (iterator.hasNext()) {
2097: virtualElement = (VirtualElement) iterator.next();
2098:
2099: virtualElement.doVisible();
2100: virtualElement.doSonore();
2101:
2102: //dispatch notifications to clients with filters on each object
2103: try {
2104: transaction = this .getPersistentManager().currentTransaction();
2105: transaction.begin();
2106:
2107: extent = this .getPersistentManager().getExtent(Filter.class, true);
2108: filter = new String("SELECT Filter FROM Filter f WHERE f.getObject()==virtualElement");
2109: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2110: filterCollection = (Collection) query.execute();
2111:
2112: transaction.commit();
2113: }
2114: catch (Exception exception) {
2115: }
2116:
2117: iterator2 = filterCollection.iterator();
2118: while (iterator2.hasNext()) {
2119: filter = (Filter) iterator2.next();
2120: if ((filter.getAccessKind() == Filter.READ_ACCESS) || (filter.getAccessKind() == Filter.READ_WRITE_ACCESS)) {
2121: this .sendNotification(filter.getRequester(), virtualElement);
2122: }
2123: }
2124:
2125: //don't send elements with a blocker
2126: found = false;
2127: iterator2 = blockerCollection.iterator();
2128: while (iterator2.hasNext() && (!found)) {
2129: found = ((((Blocker)iterator2.next()).getObject()) == virtualElement);
2130: }
2131: if (!found) {
2132:
2133: //initiate transfer
2134: if (virtualElement instanceof BackgroundWorld) {
2135: virtualElement.getBackgroundDescription().setApplicationBounds(virtualElement.getBounds());
2136: networkElement = new NetworkElement(requestID, new Transform3D(), virtualElement.getBackgroundDescription(), virtualElement.getSoundDescription(), virtualElement.getStatus());
2137: } else {
2138: //if virtualElement instanceof ObjectWorld
2139: networkElement = new NetworkElement(requestID, virtualElement.getTransform3D(), virtualElement.getGeometryDescription(), virtualElement.getSoundDescription(), virtualElement.getStatus());
2140: }
2141: networkElement.setInformation(virtualElement.getInformation());
2142: networkElement.setPrice(virtualElement.getPrice());
2143: networkElement.setCurrency(virtualElement.getCurrency());
2144: networkElement.setOthersAccessRights(Avatar.PEERLORD, virtualElement.getOthersAccessRights(Avatar.PEERLORD));
2145: networkElement.setOthersAccessRights(Avatar.PEER, virtualElement.getOthersAccessRights(Avatar.PEER));
2146: networkElement.setOthersAccessRights(Avatar.PEERVASSAL, virtualElement.getOthersAccessRights(Avatar.PEERVASSAL));
2147: networkElement.setOthersAccessRights(Avatar.VASSAL, virtualElement.getOthersAccessRights(Avatar.VASSAL));
2148: networkElement.setDesignerCapabilities(virtualElement.getDesignerCapabilities());
2149:
2150: resultCollection.add(networkElement);
2151:
2152: }
2153:
2154: }
2155:
2156: //only send updated objects and requested objects
2157: iterator = resultCollection.iterator();
2158:
2159: while (iterator.hasNext()) {
2160: networkElement = (NetworkElement) iterator.next();
2161: if (sendObject.contains(networkElement)) {
2162:
2163: }
2164: }
2165:
2166: //sendObjects;
2167: //YYYYYYYY XXX
2168: // virtualElement.setCaller();
2169: //YYYYYYYY XXXX
2170:
2171: //YYYYYYYY XXXX //manage disappearing objects doInvisible() doUnSonore()
2172:
2173: //YYYYYYYY XXXx //manage doUnLook
2174:
2175: //update objects depending on client change or dirty objects from other client access
2176:
2177: //clear dirty when every client has had a round
2178:
2179: try {
2180: transaction = this .getPersistentManager().currentTransaction();
2181: transaction.begin();
2182:
2183: extent = this .getPersistentManager().getExtent(Filter.class, true);
2184: filter = new String("SELECT BackgroundWorld FROM BackgroundWorld b WHERE b.getDirty()==true AND b.getGeometryBounds().intersects(boundingSphere)");
2185: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2186: collection1 = (Collection) query.execute();
2187:
2188: transaction.commit();
2189: }
2190: catch (Exception exception) {
2191: }
2192:
2193: try {
2194: transaction = this .getPersistentManager().currentTransaction();
2195: transaction.begin();
2196:
2197: extent = this .getPersistentManager().getExtent(Filter.class, true);
2198: filter = new String("SELECT ObjectWorld FROM ObjectWorld o WHERE o.getDirty()==true AND o.getGeometryBounds().intersects(boundingSphere)");
2199: query = this .getPersistentManager().newQuery(Filter.class, extent, filter);
2200: collection2 = (Collection) query.execute();
2201:
2202: transaction.commit();
2203: }
2204: catch (Exception exception) {
2205: }
2206:
2207: collection1.addAll(collection2);
2208:
2209: //build results and clear dirty state
2210:
2211: while (iterator.hasNext()) {
2212: ((VirtualElement)iterator.next()).clearDirty();
2213: }
2214:
2215: try {
2216: transaction = this .getPersistenceManager().currentTransaction();
2217: transaction.begin();
2218:
2219: this .getPersistentManager().refreshAll(collection);
2220:
2221: transaction.commit();
2222: }
2223: catch (Exception exception) {
2224: }
2225:
2226: //send to network
2227: return resultCollection;
2228: }
2229:
2230: private static ServerSocketFactory getServerSocketFactory(String type) {
2231:
2232: SSLContext sSLContext;
2233: KeyManagerFactory keyManagerFactory;
2234: KeyStore keyStore;
2235: char[] passphrase;
2236: SSLServerSocketFactory sSLServerSocketFactory;
2237:
2238: if (type.equals("TLS")) {
2239: try {
2240: // set up key manager to do server authentication
2241: passphrase = "passphrase".toCharArray();
2242:
2243: sSLContext = SSLContext.getInstance("TLS");
2244: keyManagerFactory = KeyManagerFactory.getInstance("SunX509");
2245: keyStore = KeyStore.getInstance("JKS");
2246:
2247: keyStore.load(new FileInputStream("testkeys"), passphrase);
2248: keyManagerFactory.init(keyStore, passphrase);
2249: sSLContext.init(keyManagerFactory.getKeyManagers(), null, null);
2250:
2251: sSLServerSocketFactory = sSLContext.getServerSocketFactory();
2252: return sSLServerSocketFactory;
2253: } catch (Exception exception) {
2254: exception.printStackTrace();
2255: }
2256: } else {
2257: return ServerSocketFactory.getDefault();
2258: }
2259: return null;
2260:
2261: }
2262:
2263:
2264: public boolean getActiveLog() {
2265:
2266: return activeLog;
2267:
2268: }
2269:
2270: public void setActiveLog(boolean log) {
2271:
2272: activeLog = log;
2273:
2274: }
2275:
2276: public void log(String string) {
2277:
2278: if (activeLog) {
2279: System.out.println(string);
2280: }
2281:
2282: }
2283:
2284: private final static HashSet filterCollection(Avatar caller, Collection collection) {
2285:
2286: Iterator iterator;
2287: Iterator iterator2;
2288: Collection passCollection;
2289: HashSet resultCollection;
2290: int relation;
2291: VirtualElement virtualElement;
2292: boolean found;
2293: Pass pass;
2294:
2295: resultCollection = new HashSet();
2296:
2297: if (caller!=null) {
2298:
2299: //objects with a pass may bypass access
2300: passCollection = caller.getPass();
2301:
2302: iterator = collection.iterator();
2303:
2304: while (iterator.hasNext()) {
2305:
2306: virtualElement = (VirtualElement) iterator.next();
2307: relation = Avatar.getFeudalRelation(caller, virtualElement.getUserOwner());
2308:
2309: if ((relation == Avatar.LORD) || (relation == Avatar.SELF)) {
2310: resultCollection.add(virtualElement);
2311: } else {
2312: if (virtualElement.getOthersAccessRights(relation) != VirtualElement.HIDDEN) {
2313: resultCollection.add(virtualElement);
2314: } else {
2315: iterator2 = passCollection.iterator();
2316: found = false;
2317: while (iterator2.hasNext() && (!found)) {
2318: pass = (Pass) iterator2.next();
2319: found = (pass.getObject() == virtualElement);
2320: }
2321: if (found) {
2322: resultCollection.add(virtualElement);
2323: }
2324: }
2325: }
2326:
2327: }
2328:
2329: }
2330:
2331: return resultCollection;
2332:
2333: }
2334:
2335:}
|