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: import java.lang.IllegalArgumentException;
0038: import java.security.PublicKey;
0039: import java.util.*;
0040: import javax.jdo.*;
0041: import javax.media.j3d.Bounds;
0042: import javax.media.j3d.BoundingSphere;
0043: import javax.media.j3d.Transform3D;
0044: import javax.vecmath.Point3d;
0045: import javax.vecmath.Vector3d;
0046:
0047: import com.db.utils.tree.*;
0048:
0049: /**
0050: */
0051:
0052: //XXXXX
0053: //track Avatar addition and deletion with Filters
0054: public class Avatar extends Object {
0055:
0056: public final static int IMMIGRATING = 1;
0057: public final static int NORMAL = 2;
0058: public final static int AWAY = 3;
0059: public final static int PAWN = 4;
0060:
0061: //NONE stands for no relation between two avatars (which are therefore not on the same worldSpot)
0062: public final static int NONE = 0;
0063: public final static int RULER = 1;
0064: public final static int LORD = 2;
0065: public final static int PEERSLORD = 4;
0066: public final static int PEER = 8;
0067: public final static int PEERSVASSAL = 16;
0068: public final static int VASSAL = 32;
0069: public final static int SELF = 64;
0070:
0071: public final static int LAST_AVATAR_KIND = (Avatar.SELF * 2) - 1;
0072:
0073: public final static int HIDDEN = 0;
0074: public final static int READ = 1;
0075: public final static int READ_WRITE = 2;
0076:
0077: //succession policies
0078: public final static int GIVE_ALL_TO_LORD = 0;
0079: public final static int SHARE_AMONG_PEER = 1;
0080: public final static int SHARE_AMONG_DIRECT_VASSALS = 2;
0081: public final static int SHARE_AMONG_VASSALS = 3;
0082: public final static int TRASH_ALL = 4;
0083:
0084: public final static int DEFAULT_SUCCESSION_POLICY = Avatar.GIVE_ALL_TO_LORD;
0085:
0086: /**
0087: * owner login (unique for a given Universe, shared between World Spots)
0088: * owner password
0089: * owner public key (send to server and other clients)
0090: * certificates (with their validity: duration, sender, receiver, eligible rights)
0091: * tickets (owner's proof of purchase of different objects or tools) (id of transaction, object, price, date, seller public key) and receipts (the counterpart of the ticket that goes to the seller) (id of transaction, object, price, date, buyer public key)
0092: * status (internal) either immigrating, normal, away (not connected or in another world spot or virtual world) or pawn (login, password, public key, certificates, tickets and receipts should be deleted as well as textual avatar information) (position and orientation should remain the same)
0093: * (tools should be designed to give the opportunity to the lord of the user to dispatch lands, vassals pawns, objects, tools, guides and even geometry and sound description of the user so that the account is really deleted) (when everything has been dispatched the avatar should be automatically removed from the server)
0094: * vassals (if any) (this is only a pointer to a query on the world spot for convenience)
0095: * pawns (virtual vassals) used when the vassal is removed but its belongings are not explicitely transfered to the user (when the vassal account is closed, but not deleted it is transmuted into a pawn) (pawns are not guides)
0096: * owner's lands (if any) (this is only a pointer to a query on the world spot for convenience)
0097: * owner's home position and orientation (if any) (must be in lands boundary) (the place where objects will try to fall if not occupied by something else when an object is imported, bought or rejected from a certain land) (if an object can't go to home, it should be stored in the inventory or action should be refused)
0098: * "Geometry description": (subclass of 3D Object)
0099: * owner's current position and orientation
0100: * skin (joint and segments replicating the H-Anim specification)
0101: * accessories (visible and audible tools worn on the body but accessible from the inventory) and their relative positions and orientations on the skin.
0102: * verbals (words that can be pronounced by the avatar's skin mouth as skin deformation and sound emission)
0103: * movements (overall body movements)
0104: * gestures (particular joint and segment combination movements without global movement)
0105: * Sound description (sounds that correspond to movements or sound of voice) (sounds from accessories are managed by the accessory itself) (subclass of 3D Object)
0106: * Capabilities (4 booleans grant access for invited lords, peers, peers vassals and vassals) (ancestors of a user can always collide, see and hear a user if they have requested so):
0107: * collidable
0108: * visible
0109: * sonore
0110: * hands (automatically accept to shake hands, but still requires that another user that wants to shake bounces into the avatar)
0111: * textual avatar information (how the user self perceives its avatar, name, firstame, sex, age, e-mail, address, phone in an hashtable with empty fields)
0112: * inventory (the pocket of the user in which to store collected objects, useful tools and guides)
0113: * notification filter
0114: **/
0115:
0116: private final static String STRING_NAME = "Name";
0117: private final static String STRING_FIRSTNAME = "Firstname";
0118: private final static String STRING_SEX = "Sex";
0119: private final static String STRING_AGE = "Age";
0120: private final static String STRING_E_MAIL = "e-mail";
0121: private final static String STRING_ADDRESS = "Address";
0122: private final static String STRING_PHONE = "Phone";
0123:
0124: private UniverseServer universeServer;
0125: private LoginInformation loginInformation;
0126: private Hashtable information;
0127: private int status;
0128: private HashSet vassals;
0129: private Transform3D homePosition;
0130: private Skin skin;
0131: private HashSet inventory;
0132: private int landSuccessionPolicy;
0133: private int objectWorldSuccessionPolicy;
0134: private int backgroundWorldSuccessionPolicy;
0135:
0136: //In a big community, lords will probably be notified about many vassals actions (requests from their vassals to access land...). This should rapidly create an
0137: //unwanted network overload as well as a lot of unwanted junk data. A filter mechanism is proposed in which users can decide not to be notified when a
0138: //vassal makes a request (the notification message is not send from the server). The filter is a list of pairs key-key value.
0139: //The key mentions the Object concerned and the kind of request:
0140: // Request field read - field write (of an object, tool, guide, avatar, land, World Spot)
0141: // Request action execution (of an object, tool, guide, avatar, land, World Spot), the action may involve creation, modification or deletion of an object,
0142: // tool, guide, avatar, land.
0143: //The key-value is given with 6 booleans to grant notification about users' actions for the owner himself, lords, invited lords, peers, peers vassals and vassals.
0144: //Using the notification filter, users can choose not to see or hear or collide from objects, tools, guides, avatars, owners (corresponding fields in the avatar).
0145: //Users that make no filtering will have a log of every actions about themselves, lords, invited lords, peers, peers vassals and vassals. Since lords can also
0146: //decide to refuse to be queried, this log can be incomplete. The only complete log is the one of the top lord if he requests no filtering.
0147: //
0148: //the notification filter mentions positive notification
0149: //users are notified of nothing (except answers to their requests) if they do not request anything
0150: //if a user want to be notified of a lord visiting one of its lands then he has to add en entry in the notification filter
0151: //When a user doesn't want some automatic requests he sends to be completed
0152: //For example if he doesn't want to hear from someone
0153: //when a user wants to create a new account, all its parent must have vassalsMayCreateAccounts set to true;
0154: private boolean vassalsMayCreateAccounts;
0155:
0156: private Avatar() {
0157:
0158: throw new IllegalArgumentException(
0159: "An avatar must have a universeServer and a loginInformation.");
0160:
0161: }
0162:
0163: public Avatar(UniverseServer universeServer,
0164: LoginInformation loginInformation) {
0165:
0166: this .loginInformation = loginInformation;
0167: this .universeServer = universeServer;
0168: this .information = new Hashtable();
0169: this .status = Avatar.IMMIGRATING;
0170: this .vassals = new HashSet();
0171: this .inventory = new HashSet();
0172: this .vassalsMayCreateAccounts = true;
0173: this .landSuccessionPolicy = DEFAULT_SUCCESSION_POLICY;
0174: this .objectWorldSuccessionPolicy = DEFAULT_SUCCESSION_POLICY;
0175: this .backgroundWorldSuccessionPolicy = DEFAULT_SUCCESSION_POLICY;
0176:
0177: }
0178:
0179: public final LoginInformation getLoginInformation() {
0180:
0181: return loginInformation;
0182:
0183: }
0184:
0185: public final UniverseServer getUniverseServer() {
0186:
0187: return this .universeServer;
0188:
0189: }
0190:
0191: private final PersistenceManager getPersistenceManager() {
0192:
0193: return this .universeServer.getPersistenceManager();
0194:
0195: }
0196:
0197: // avatar name, firstame, sex, age, e-mail, address, phone
0198: public final Hashtable getInformation() {
0199:
0200: return information;
0201:
0202: }
0203:
0204: public final String getInformation(String key) {
0205:
0206: return (String) information.get(key);
0207:
0208: }
0209:
0210: public final void setLoginInformation(
0211: LoginInformation loginInformation) {
0212:
0213: if (this .loginInformation
0214: .checkLoginAndPassword(loginInformation)) {
0215: this .loginInformation = loginInformation;
0216: }
0217:
0218: }
0219:
0220: // be cautious with this method as it obliterates the avatar name, firstame, sex, age, e-mail, address, phone
0221: //obliterates every previously stored information including reserved fields
0222: public final void setInformation(Hashtable information) {
0223:
0224: this .information = information;
0225:
0226: }
0227:
0228: //use the corresponding method to set the individual default fields
0229: public final void addInformation(String key, String keyValue) {
0230:
0231: //check if it is a reserved field or not
0232: if ((key != Avatar.STRING_NAME)
0233: && (key != Avatar.STRING_FIRSTNAME)
0234: && (key != Avatar.STRING_SEX)
0235: && (key != Avatar.STRING_AGE)
0236: && (key != Avatar.STRING_E_MAIL)
0237: && (key != Avatar.STRING_ADDRESS)
0238: && (key != Avatar.STRING_PHONE)) {
0239: this .information.put(key, keyValue);
0240: } else {
0241: throw new IllegalArgumentException(
0242: "You can't add directely Information on the restricted fields.");
0243: }
0244:
0245: }
0246:
0247: public final void removeInformation(String key) {
0248:
0249: //check if it is a reserved field or not
0250: if ((key != Avatar.STRING_NAME)
0251: && (key != Avatar.STRING_FIRSTNAME)
0252: && (key != Avatar.STRING_SEX)
0253: && (key != Avatar.STRING_AGE)
0254: && (key != Avatar.STRING_E_MAIL)
0255: && (key != Avatar.STRING_ADDRESS)
0256: && (key != Avatar.STRING_PHONE)) {
0257: this .information.remove(key);
0258: } else {
0259: throw new IllegalArgumentException(
0260: "You can't remove directely Information on the restricted fields.");
0261: }
0262:
0263: }
0264:
0265: //uses the key Name
0266: public String getAvatarName() {
0267:
0268: return this .getInformation(Avatar.STRING_NAME);
0269:
0270: }
0271:
0272: //uses the key Name
0273: public void setAvatarName(String name) {
0274:
0275: this .addInformation(Avatar.STRING_NAME, name);
0276:
0277: }
0278:
0279: //uses the key Firstname
0280: public String getAvatarFirstname() {
0281:
0282: return this .getInformation(Avatar.STRING_FIRSTNAME);
0283:
0284: }
0285:
0286: //uses the key Firstname
0287: public void setAvatarFirstname(String firstname) {
0288:
0289: this .addInformation(Avatar.STRING_FIRSTNAME, firstname);
0290:
0291: }
0292:
0293: //uses the key Sex (should be either male, female, other)
0294: public String getAvatarSex() {
0295:
0296: return this .getInformation(Avatar.STRING_SEX);
0297:
0298: }
0299:
0300: //uses the key Sex (should be either male, female, other)
0301: public void setAvatarSex(String sex) {
0302:
0303: this .addInformation(Avatar.STRING_SEX, sex);
0304:
0305: }
0306:
0307: //uses the key Age (this is a String with numerical caracters only)
0308: public String getAvatarAge() {
0309:
0310: return this .getInformation(Avatar.STRING_AGE);
0311:
0312: }
0313:
0314: //uses the key Age (this is a String with numerical caracters only)
0315: public void setAvatarAge(String age) {
0316:
0317: this .addInformation(Avatar.STRING_AGE, age);
0318:
0319: }
0320:
0321: //uses the key EMail
0322: public String getAvatarEMail() {
0323:
0324: return this .getInformation(Avatar.STRING_E_MAIL);
0325:
0326: }
0327:
0328: //uses the key EMail
0329: public void setAvatarEMail(String eMail) {
0330:
0331: this .addInformation(Avatar.STRING_E_MAIL, eMail);
0332:
0333: }
0334:
0335: //uses the key Address (real world address, virtual home is given with access to home position)
0336: public String getAvatarAddress() {
0337:
0338: return this .getInformation(Avatar.STRING_ADDRESS);
0339:
0340: }
0341:
0342: //uses the key Address (real world address, virtual home is given with access to home position)
0343: public void setAvatarAddress(String address) {
0344:
0345: this .addInformation(Avatar.STRING_ADDRESS, address);
0346:
0347: }
0348:
0349: //uses the key Phone (real phone number, mostly useless)
0350: public String getAvatarPhone() {
0351:
0352: return this .getInformation(Avatar.STRING_PHONE);
0353:
0354: }
0355:
0356: //uses the key Phone (real phone number, mostly useless)
0357: public void setAvatarPhone(String phone) {
0358:
0359: this .addInformation(Avatar.STRING_PHONE, phone);
0360:
0361: }
0362:
0363: public final Collection getPass() {
0364:
0365: Transaction transaction;
0366: Extent extent;
0367: Query query;
0368: String filter;
0369: Collection collection;
0370:
0371: refreshPass();
0372:
0373: try {
0374: transaction = this .getPersistenceManager()
0375: .currentTransaction();
0376: transaction.begin();
0377:
0378: extent = this .getPersistenceManager().getExtent(Pass.class,
0379: true);
0380: filter = new String(
0381: "SELECT Pass FROM Pass p WHERE p.getReceiver()==this");
0382: query = this .getPersistenceManager().newQuery(Pass.class,
0383: extent, filter);
0384: collection = (Collection) query.execute();
0385:
0386: transaction.commit();
0387:
0388: return collection;
0389:
0390: } catch (Exception exception) {
0391:
0392: return null;
0393:
0394: }
0395:
0396: }
0397:
0398: //pass is not plural here
0399: //does automatically add pass to receiver of the pass
0400: public final void addPass(Pass pass) {
0401:
0402: Transaction transaction;
0403:
0404: refreshPass();
0405:
0406: //may be we should check Pass does not already exist
0407: if (pass != null) {
0408: if ((pass.getSender() == this )
0409: || (pass.getReceiver() == this )) {
0410: if ((pass.getEndDate() > this .getUniverseServer()
0411: .getServerTime())
0412: && (pass.getStartDate() > universeServer
0413: .getServerTime())) {
0414:
0415: try {
0416: transaction = this .getPersistenceManager()
0417: .currentTransaction();
0418: transaction.begin();
0419:
0420: this .getPersistenceManager().makePersistent(
0421: pass);
0422:
0423: transaction.commit();
0424:
0425: } catch (Exception exception) {
0426: }
0427: }
0428: }
0429: }
0430:
0431: }
0432:
0433: //pass is not plural here
0434: //does automatically remove pass to sender of the pass
0435: //you remove pass you received
0436: public final void removePass(Pass pass) {
0437:
0438: Transaction transaction;
0439:
0440: refreshPass();
0441:
0442: if (pass.getReceiver() == this ) {
0443: try {
0444: transaction = this .getPersistenceManager()
0445: .currentTransaction();
0446: transaction.begin();
0447:
0448: this .getPersistenceManager().deletePersistent(pass);
0449:
0450: transaction.commit();
0451:
0452: } catch (Exception exception) {
0453: }
0454: }
0455:
0456: }
0457:
0458: private void removeAllPass() {
0459:
0460: Iterator iterator;
0461:
0462: iterator = this .getPass().iterator();
0463: while (iterator.hasNext()) {
0464: this .removePass((Pass) iterator.next());
0465: }
0466:
0467: }
0468:
0469: private void refreshPass() {
0470:
0471: Transaction transaction;
0472: Extent extent;
0473: Query query;
0474: String filter;
0475: Collection collection;
0476:
0477: try {
0478: transaction = this .getPersistenceManager()
0479: .currentTransaction();
0480: transaction.begin();
0481:
0482: extent = this .getPersistenceManager().getExtent(Pass.class,
0483: true);
0484: filter = new String(
0485: "DELETE Pass FROM Pass p WHERE p.getReceiver()==this AND p.getEndDate()<=this.getUniverseServer().getServerTime()");
0486: query = this .getPersistenceManager().newQuery(Pass.class,
0487: extent, filter);
0488: collection = (Collection) query.execute();
0489:
0490: transaction.commit();
0491:
0492: } catch (Exception exception) {
0493: }
0494:
0495: }
0496:
0497: public final Collection getTicketsOrReceipts() {
0498:
0499: Transaction transaction;
0500: Extent extent;
0501: Query query;
0502: String filter;
0503: Collection collection;
0504:
0505: try {
0506: transaction = this .getPersistenceManager()
0507: .currentTransaction();
0508: transaction.begin();
0509:
0510: extent = this .getPersistenceManager().getExtent(
0511: Ticket.class, true);
0512: filter = new String(
0513: "SELECT Ticket FROM Ticket t WHERE t.getSellerOrBuyer()==this");
0514: query = this .getPersistenceManager().newQuery(Ticket.class,
0515: extent, filter);
0516: collection = (Collection) query.execute();
0517:
0518: transaction.commit();
0519:
0520: return collection;
0521:
0522: } catch (Exception exception) {
0523:
0524: return null;
0525:
0526: }
0527:
0528: }
0529:
0530: //because method is protected we do not check if Ticket is emited or received by this avatar which should always be the case
0531: protected final void addTicketOrReceipt(Ticket ticketOrReceipt) {
0532:
0533: Transaction transaction;
0534:
0535: //may be we should check Ticket does not already exist
0536: try {
0537: transaction = this .getPersistenceManager()
0538: .currentTransaction();
0539: transaction.begin();
0540:
0541: this .getPersistenceManager()
0542: .makePersistent(ticketOrReceipt);
0543:
0544: transaction.commit();
0545:
0546: } catch (Exception exception) {
0547: }
0548:
0549: }
0550:
0551: public final void removeTicketOrReceipt(Ticket ticketOrReceipt) {
0552:
0553: Transaction transaction;
0554:
0555: if (ticketOrReceipt.getSellerOrBuyer() == this ) {
0556: try {
0557: transaction = this .getPersistenceManager()
0558: .currentTransaction();
0559: transaction.begin();
0560:
0561: this .getPersistenceManager().deletePersistent(
0562: ticketOrReceipt);
0563:
0564: transaction.commit();
0565:
0566: } catch (Exception exception) {
0567: }
0568:
0569: }
0570:
0571: }
0572:
0573: private void removeAllTicketOrReceipts() {
0574:
0575: Iterator iterator;
0576:
0577: iterator = this .getTicketsOrReceipts().iterator();
0578: while (iterator.hasNext()) {
0579: this .removeTicketOrReceipt((Ticket) iterator.next());
0580: }
0581:
0582: }
0583:
0584: public final int getStatus() {
0585:
0586: return this .status;
0587:
0588: }
0589:
0590: //calls only valid by the system
0591: //client calls are useless
0592: //valid values range for
0593: //Avatar.IMMIGRATING; (when moving between worldspots or moving between gates) (not first connection) (may be used to display special information on arrival) (this status should not last and change automatically to Avatar.NORMAL)
0594: //Avatar.NORMAL;
0595: //Avatar.AWAY;
0596: //Avatar.PAWN;
0597: //Once a pawn, an avatar can't have it's status restored back
0598: //this is in other words the way accounts are closed
0599: public final void setStatus(int status) {
0600:
0601: HashSet hashSet;
0602: Iterator iterator;
0603: Avatar avatar;
0604: Transaction transaction;
0605:
0606: if ((status >= Avatar.IMMIGRATING) && (status <= Avatar.PAWN)) {
0607: if (this .status != Avatar.PAWN) {
0608: if (status == Avatar.PAWN) {
0609: pawnUser();
0610: } else {
0611: if ((this .status != Avatar.AWAY)
0612: && (status == Avatar.AWAY)) {
0613: //Warn server to close connection
0614: this .getUniverseServer().closeConnection(this );
0615: }
0616: this .status = status;
0617: }
0618: }
0619: }
0620:
0621: }
0622:
0623: //gets succession policies in a 3 int array that provides landPolicy, objectWorldPolicy, backgroundWorldPolicy in that order
0624: public final int[] getSuccessionPolicies() {
0625:
0626: int[] policies;
0627:
0628: policies = new int[3];
0629: policies[0] = this .landSuccessionPolicy;
0630: policies[1] = this .objectWorldSuccessionPolicy;
0631: policies[2] = this .backgroundWorldSuccessionPolicy;
0632:
0633: return policies;
0634:
0635: }
0636:
0637: //can only be called by self
0638: //landPolicy.TRASH_ALL is forbidden for this implementation (makes holes in the worldspot)
0639: public final void setSuccessionPolicy(int landPolicy,
0640: int objectWorldPolicy, int backgroundWorldPolicy) {
0641:
0642: if ((landPolicy >= GIVE_ALL_TO_LORD)
0643: && (landPolicy <= SHARE_AMONG_VASSALS)) {
0644: this .landSuccessionPolicy = landPolicy;
0645: }
0646: if ((objectWorldPolicy >= GIVE_ALL_TO_LORD)
0647: && (objectWorldPolicy <= TRASH_ALL)) {
0648: this .objectWorldSuccessionPolicy = objectWorldPolicy;
0649: }
0650: if ((backgroundWorldPolicy >= GIVE_ALL_TO_LORD)
0651: && (backgroundWorldPolicy <= TRASH_ALL)) {
0652: this .backgroundWorldSuccessionPolicy = backgroundWorldPolicy;
0653: }
0654:
0655: }
0656:
0657: //closes client-server connection: this is a logout (or a kick-out)
0658: public final void disconnectUser() {
0659:
0660: this .setStatus(Avatar.AWAY);
0661:
0662: }
0663:
0664: //user is automatically deleted when the Pawn belongings have all been transfered or deleted
0665: //hierarchy may therefore sometimes collapse and users should be notified (their vassals should be updated)
0666: //equivalent to this.setStatus(Avatar.PAWN);
0667: //can't pawn ruler
0668: //a pool is opened in which all belongings are put for 60 days depending of succession policy
0669: //uses sytem time not universeServer time (offset difference)
0670: //Trashing land is a bas idea since it makes holes in the worldspot and is therefore forbidden for this implementation
0671: public final void pawnUser() {
0672:
0673: Avatar lord;
0674: Transaction transaction;
0675: Extent extent;
0676: Query query;
0677: String filter;
0678: Collection collection;
0679: Iterator iterator;
0680: boolean poolExists;
0681: Pool pool;
0682: Date date;
0683: Avatar avatar;
0684: VirtualElement virtualElement;
0685: Bounds bounds;
0686:
0687: lord = Avatar.getLord(this );
0688:
0689: //can't pawn ruler
0690: if (lord != null) {
0691:
0692: if (this .status != Avatar.PAWN) {
0693:
0694: synchronized (this ) {
0695:
0696: this .disconnectUser();
0697: this .status = Avatar.PAWN;
0698:
0699: //throw everything out of inventory
0700: this .removeAllInventoryEntries();
0701:
0702: poolExists = false;
0703: pool = null;
0704: //get VirtualElements: Land
0705: collection = this .getLands();
0706:
0707: //do something of VirtualElements
0708: if (this .landSuccessionPolicy == Avatar.GIVE_ALL_TO_LORD) {
0709: this .removeAllLands();
0710: } else {
0711: if (this .landSuccessionPolicy == Avatar.SHARE_AMONG_PEER) {
0712: pool = Avatar.getWorldSpot(this ).startPool(
0713: this );
0714: poolExists = true;
0715: iterator = collection.iterator();
0716: date = new Date(System.currentTimeMillis()
0717: + 1000 * 3600 * 24 * 60);
0718: while (iterator.hasNext()) {
0719: virtualElement = (VirtualElement) iterator
0720: .next();
0721: pool.dontSellUnder(this ,
0722: virtualElement, date);
0723: }
0724: iterator = lord.getVassals().iterator();
0725: while (iterator.hasNext()) {
0726: avatar = (Avatar) iterator.next();
0727: pool.comeIntoPool(avatar);
0728: }
0729: } else {
0730: if (this .landSuccessionPolicy == Avatar.SHARE_AMONG_DIRECT_VASSALS) {
0731: pool = Avatar.getWorldSpot(this )
0732: .startPool(this );
0733: poolExists = true;
0734: iterator = collection.iterator();
0735: date = new Date(System
0736: .currentTimeMillis()
0737: + 1000 * 3600 * 24 * 60);
0738: while (iterator.hasNext()) {
0739: virtualElement = (VirtualElement) iterator
0740: .next();
0741: pool.dontSellUnder(this ,
0742: virtualElement, date);
0743: }
0744: iterator = this .getVassals().iterator();
0745: while (iterator.hasNext()) {
0746: avatar = (Avatar) iterator.next();
0747: pool.comeIntoPool(avatar);
0748: }
0749: } else {
0750: if (this .landSuccessionPolicy == Avatar.SHARE_AMONG_VASSALS) {
0751: pool = Avatar.getWorldSpot(this )
0752: .startPool(this );
0753: poolExists = true;
0754: iterator = collection.iterator();
0755: date = new Date(System
0756: .currentTimeMillis()
0757: + 1000 * 3600 * 24 * 60);
0758: while (iterator.hasNext()) {
0759: virtualElement = (VirtualElement) iterator
0760: .next();
0761: pool.dontSellUnder(this ,
0762: virtualElement, date);
0763: }
0764: iterator = this .getAllVassals()
0765: .iterator();
0766: while (iterator.hasNext()) {
0767: avatar = (Avatar) iterator
0768: .next();
0769: pool.comeIntoPool(avatar);
0770: }
0771: } else {
0772: //Avatar.TRASH_ALL
0773: //we actually do not trash all lands because this would create a hole in the worldspot
0774: this .removeAllLands();
0775:
0776: }
0777: }
0778: }
0779: }
0780:
0781: //get VirtualElements: ObjectWorld
0782: collection = this .getObjectWorlds();
0783:
0784: //do something of VirtualElements
0785: if (this .objectWorldSuccessionPolicy == Avatar.GIVE_ALL_TO_LORD) {
0786: Avatar.getWorldSpot(this ).getTrade()
0787: .exchange(
0788: this ,
0789: (VirtualElement[]) collection
0790: .toArray(), lord,
0791: new VirtualElement[0]);
0792: } else {
0793: if (this .objectWorldSuccessionPolicy == Avatar.SHARE_AMONG_PEER) {
0794: if (!poolExists) {
0795: pool = Avatar.getWorldSpot(this )
0796: .startPool(this );
0797: }
0798: iterator = collection.iterator();
0799: date = new Date(System.currentTimeMillis()
0800: + 1000 * 3600 * 24 * 60);
0801: while (iterator.hasNext()) {
0802: virtualElement = (VirtualElement) iterator
0803: .next();
0804: pool.dontSellUnder(this ,
0805: virtualElement, date);
0806: }
0807: iterator = lord.getVassals().iterator();
0808: while (iterator.hasNext()) {
0809: avatar = (Avatar) iterator.next();
0810: pool.comeIntoPool(avatar);
0811: }
0812: } else {
0813: if (this .objectWorldSuccessionPolicy == Avatar.SHARE_AMONG_DIRECT_VASSALS) {
0814: if (!poolExists) {
0815: pool = Avatar.getWorldSpot(this )
0816: .startPool(this );
0817: }
0818: iterator = collection.iterator();
0819: date = new Date(System
0820: .currentTimeMillis()
0821: + 1000 * 3600 * 24 * 60);
0822: while (iterator.hasNext()) {
0823: virtualElement = (VirtualElement) iterator
0824: .next();
0825: pool.dontSellUnder(this ,
0826: virtualElement, date);
0827: }
0828: iterator = this .getVassals().iterator();
0829: while (iterator.hasNext()) {
0830: avatar = (Avatar) iterator.next();
0831: pool.comeIntoPool(avatar);
0832: }
0833: } else {
0834: if (this .objectWorldSuccessionPolicy == Avatar.SHARE_AMONG_VASSALS) {
0835: if (!poolExists) {
0836: pool = Avatar
0837: .getWorldSpot(this )
0838: .startPool(this );
0839: }
0840: iterator = collection.iterator();
0841: date = new Date(System
0842: .currentTimeMillis()
0843: + 1000 * 3600 * 24 * 60);
0844: while (iterator.hasNext()) {
0845: virtualElement = (VirtualElement) iterator
0846: .next();
0847: pool.dontSellUnder(this ,
0848: virtualElement, date);
0849: }
0850: iterator = this .getAllVassals()
0851: .iterator();
0852: while (iterator.hasNext()) {
0853: avatar = (Avatar) iterator
0854: .next();
0855: pool.comeIntoPool(avatar);
0856: }
0857: } else {
0858: //Avatar.TRASH_ALL
0859: iterator = collection.iterator();
0860: while (iterator.hasNext()) {
0861: virtualElement = (VirtualElement) iterator
0862: .next();
0863: virtualElement
0864: .deleteVirtualElement(
0865: this ,
0866: virtualElement);
0867: }
0868: }
0869: }
0870: }
0871: }
0872:
0873: //get VirtualElements: BackgroundWorld
0874:
0875: //do something of VirtualElements
0876: if (this .backgroundWorldSuccessionPolicy == Avatar.GIVE_ALL_TO_LORD) {
0877: this .removeAllBackgroundWorlds();
0878: } else {
0879: collection = this .getBackgroundWorlds();
0880: if (this .backgroundWorldSuccessionPolicy == Avatar.SHARE_AMONG_PEER) {
0881: if (!poolExists) {
0882: pool = Avatar.getWorldSpot(this )
0883: .startPool(this );
0884: }
0885: iterator = collection.iterator();
0886: date = new Date(System.currentTimeMillis()
0887: + 1000 * 3600 * 24 * 60);
0888: while (iterator.hasNext()) {
0889: virtualElement = (VirtualElement) iterator
0890: .next();
0891: pool.dontSellUnder(this ,
0892: virtualElement, date);
0893: }
0894: iterator = lord.getVassals().iterator();
0895: while (iterator.hasNext()) {
0896: avatar = (Avatar) iterator.next();
0897: pool.comeIntoPool(avatar);
0898: }
0899: } else {
0900: if (this .backgroundWorldSuccessionPolicy == Avatar.SHARE_AMONG_DIRECT_VASSALS) {
0901: if (!poolExists) {
0902: pool = Avatar.getWorldSpot(this )
0903: .startPool(this );
0904: }
0905: iterator = collection.iterator();
0906: date = new Date(System
0907: .currentTimeMillis()
0908: + 1000 * 3600 * 24 * 60);
0909: while (iterator.hasNext()) {
0910: virtualElement = (VirtualElement) iterator
0911: .next();
0912: pool.dontSellUnder(this ,
0913: virtualElement, date);
0914: }
0915: iterator = this .getVassals().iterator();
0916: while (iterator.hasNext()) {
0917: avatar = (Avatar) iterator.next();
0918: pool.comeIntoPool(avatar);
0919: }
0920: } else {
0921: if (this .backgroundWorldSuccessionPolicy == Avatar.SHARE_AMONG_VASSALS) {
0922: if (!poolExists) {
0923: pool = Avatar
0924: .getWorldSpot(this )
0925: .startPool(this );
0926: }
0927: iterator = collection.iterator();
0928: date = new Date(System
0929: .currentTimeMillis()
0930: + 1000 * 3600 * 24 * 60);
0931: while (iterator.hasNext()) {
0932: virtualElement = (VirtualElement) iterator
0933: .next();
0934: pool.dontSellUnder(this ,
0935: virtualElement, date);
0936: }
0937: iterator = this .getAllVassals()
0938: .iterator();
0939: while (iterator.hasNext()) {
0940: avatar = (Avatar) iterator
0941: .next();
0942: pool.comeIntoPool(avatar);
0943: }
0944: } else {
0945: //Avatar.TRASH_ALL
0946: iterator = collection.iterator();
0947: while (iterator.hasNext()) {
0948: virtualElement = (VirtualElement) iterator
0949: .next();
0950: virtualElement
0951: .deleteVirtualElement(
0952: this ,
0953: virtualElement);
0954: }
0955: }
0956: }
0957: }
0958: }
0959:
0960: //we have to remove some fields and notify parent
0961: //(login, password, public key, certificates, tickets and receipts should be deleted as well as textual avatar information)
0962: //(position and orientation should remain the same)
0963: this .loginInformation = null;
0964: this .setInformation(null);
0965: //pass should remain valid
0966: //tickets and receipts are deleted as the last step of avatar deletion
0967:
0968: this .removeAllBlockers();
0969: this .removeAllFilters();
0970:
0971: //database should refresh this
0972:
0973: }
0974: }
0975: }
0976:
0977: }
0978:
0979: //some avatars may not have a client
0980: //if their status is immigrating, away or pawn
0981: public boolean avatarHasClient() {
0982:
0983: return (this .status == Avatar.NORMAL);
0984: }
0985:
0986: //every vassal whether pawn of not
0987: public final HashSet getVassals() {
0988:
0989: return this .vassals;
0990:
0991: }
0992:
0993: //further calls about vassals, pawns and lands are actually queries to the database
0994: //these are pointers to real objects stored in the World Spot
0995:
0996: //vassal is reParented to be a vassal of avatar
0997: //this is equivalent to Avatar.moveUserInHierarchy(vassal, this, Avatar.getWorldsSpot(this).getRuler());
0998: protected final void addVassal(Avatar vassal) {
0999:
1000: this .moveUserInHierarchy(vassal, this );
1001:
1002: }
1003:
1004: public final void addVassal(Avatar vassal, Avatar agreeingParent) {
1005:
1006: this .moveUserInHierarchy(vassal, this , agreeingParent);
1007:
1008: }
1009:
1010: //this call is equivalent to: Avatar.moveUserInHierarchy(vassal, vassal.getLord().getLord(), vassal.getLord().getLord());
1011: //receiving Lord should be able to accept parent
1012: //vassal must be a vassal of this avatar and avatar mustn't be a ruler
1013: protected final void removeVassal(Avatar vassal) {
1014:
1015: if ((!isRuler(this )) && (this .vassals.contains(vassal))) {
1016: this .moveUserInHierarchy(vassal, Avatar.getLord(Avatar
1017: .getLord(vassal)));
1018: }
1019:
1020: }
1021:
1022: public final void removeVassal(Avatar vassal, Avatar agreeingParent) {
1023:
1024: if ((!isRuler(this )) && (this .vassals.contains(vassal))) {
1025: this .moveUserInHierarchy(vassal, Avatar.getLord(Avatar
1026: .getLord(vassal)), agreeingParent);
1027: }
1028:
1029: }
1030:
1031: private final void createVassal(Avatar vassal) {
1032: //since this is a private method, avatar is believed to exist and not be a vassal of any avatar
1033:
1034: this .vassals.add(vassal);
1035:
1036: }
1037:
1038: private final void killVassal(Avatar vassal) {
1039: //since this is a private method, avatar is believed to exist and be a vassal of this
1040:
1041: this .vassals.remove(vassal);
1042:
1043: }
1044:
1045: //only pawn vassals
1046: public final HashSet getPawns() {
1047:
1048: HashSet hashSet;
1049: Iterator iterator;
1050: Avatar avatar;
1051:
1052: hashSet = new HashSet();
1053: iterator = this .vassals.iterator();
1054: while (iterator.hasNext()) {
1055: avatar = (Avatar) iterator.next();
1056: if (avatar.getStatus() == Avatar.PAWN) {
1057: hashSet.add(avatar);
1058: }
1059: }
1060:
1061: return hashSet;
1062:
1063: }
1064:
1065: public final Collection getObjectWorlds() {
1066:
1067: Transaction transaction;
1068: Extent extent;
1069: Query query;
1070: String filter;
1071: Collection collection;
1072:
1073: try {
1074: transaction = this .getPersistenceManager()
1075: .currentTransaction();
1076: transaction.begin();
1077:
1078: extent = this .getPersistenceManager().getExtent(
1079: ObjectWorld.class, true);
1080: filter = new String(
1081: "SELECT ObjectWorld FROM ObjectWorld o WHERE o.getUserOwner()==this");
1082: query = this .getPersistenceManager().newQuery(
1083: ObjectWorld.class, extent, filter);
1084: collection = (Collection) query.execute();
1085:
1086: transaction.commit();
1087:
1088: return collection;
1089:
1090: } catch (Exception exception) {
1091:
1092: return null;
1093:
1094: }
1095:
1096: }
1097:
1098: public final Collection getLands() {
1099:
1100: Transaction transaction;
1101: Extent extent;
1102: Query query;
1103: String filter;
1104: Collection collection;
1105:
1106: try {
1107: transaction = this .getPersistenceManager()
1108: .currentTransaction();
1109: transaction.begin();
1110:
1111: extent = this .getPersistenceManager().getExtent(Land.class,
1112: true);
1113: filter = new String(
1114: "SELECT Land FROM Land l WHERE l.getUserOwner()==this");
1115: query = this .getPersistenceManager().newQuery(Land.class,
1116: extent, filter);
1117: collection = (Collection) query.execute();
1118:
1119: transaction.commit();
1120:
1121: return collection;
1122:
1123: } catch (Exception exception) {
1124:
1125: return null;
1126:
1127: }
1128:
1129: }
1130:
1131: //land ownership is transfered to this avatar
1132: protected final void addLand(Land land) {
1133:
1134: Land[] lands;
1135:
1136: if ((land != null) && (land.getUserOwner() != this )) {
1137: lands = new Land[1];
1138: lands[0] = land;
1139: Avatar.getWorldSpot(this ).getTrade().exchange(
1140: land.getUserOwner(), lands, this , null);
1141: }
1142:
1143: }
1144:
1145: //land is reparented to this.getLord() if possible
1146: public final void removeLand(Land land) {
1147:
1148: Avatar avatar;
1149: Land[] lands;
1150:
1151: avatar = Avatar.getLord(this );
1152: if ((avatar != null) && (land != null)
1153: && (land.getUserOwner() == this )) {
1154: lands = new Land[1];
1155: lands[0] = land;
1156: Avatar.getWorldSpot(this ).getTrade().exchange(this , lands,
1157: avatar, null);
1158: }
1159:
1160: }
1161:
1162: //not valid for a ruler
1163: private final void removeAllLands() {
1164:
1165: Avatar.getWorldSpot(this ).getTrade().exchange(this ,
1166: (VirtualElement[]) this .getLands().toArray(),
1167: Avatar.getLord(this ), new VirtualElement[0]);
1168:
1169: }
1170:
1171: public final Collection getBackgroundWorlds() {
1172:
1173: Transaction transaction;
1174: Extent extent;
1175: Query query;
1176: String filter;
1177: Collection collection;
1178:
1179: try {
1180: transaction = this .getPersistenceManager()
1181: .currentTransaction();
1182: transaction.begin();
1183:
1184: extent = this .getPersistenceManager().getExtent(
1185: BackgroundWorld.class, true);
1186: filter = new String(
1187: "SELECT BackgroundWorld FROM BackgroundWorld b WHERE b.getUserOwner()==this");
1188: query = this .getPersistenceManager().newQuery(
1189: BackgroundWorld.class, extent, filter);
1190: collection = (Collection) query.execute();
1191:
1192: transaction.commit();
1193:
1194: return collection;
1195:
1196: } catch (Exception exception) {
1197:
1198: return null;
1199:
1200: }
1201:
1202: }
1203:
1204: //backgoundWorld ownership is transfered to this avatar
1205: protected final void addBackgoundWorld(
1206: BackgroundWorld backgroundWorld) {
1207:
1208: BackgroundWorld[] backgroundWorlds;
1209:
1210: if ((backgroundWorld != null)
1211: && (backgroundWorld.getUserOwner() != this )) {
1212: backgroundWorlds = new BackgroundWorld[1];
1213: backgroundWorlds[0] = backgroundWorld;
1214: Avatar.getWorldSpot(this ).getTrade().exchange(
1215: backgroundWorld.getUserOwner(), backgroundWorlds,
1216: this , null);
1217: }
1218:
1219: }
1220:
1221: //backgroundWorld is reparented to this.getLord() if possible
1222: public final void removeBackgroundWorld(
1223: BackgroundWorld backgroundWorld) {
1224:
1225: Avatar avatar;
1226: BackgroundWorld[] backgroundWorlds;
1227:
1228: avatar = Avatar.getLord(this );
1229: if ((avatar != null) && (backgroundWorld != null)
1230: && (backgroundWorld.getUserOwner() == this )) {
1231: backgroundWorlds = new BackgroundWorld[1];
1232: backgroundWorlds[0] = backgroundWorld;
1233: Avatar.getWorldSpot(this ).getTrade().exchange(this ,
1234: backgroundWorlds, avatar, null);
1235: }
1236:
1237: }
1238:
1239: //not valid for a ruler
1240: private final void removeAllBackgroundWorlds() {
1241:
1242: Avatar.getWorldSpot(this ).getTrade()
1243: .exchange(
1244: this ,
1245: (VirtualElement[]) this .getBackgroundWorlds()
1246: .toArray(), Avatar.getLord(this ),
1247: new VirtualElement[0]);
1248:
1249: }
1250:
1251: public final Transform3D getHomePosition() {
1252:
1253: return this .homePosition;
1254:
1255: }
1256:
1257: public final void setHomePosition(Transform3D homePosition) {
1258:
1259: if (this .checkHome(homePosition)) {
1260: this .homePosition = homePosition;
1261: }
1262:
1263: }
1264:
1265: //sets a home using a land if one exists eventually overwriting the existing home position
1266: protected final void createHome() {
1267:
1268: Transaction transaction;
1269: Extent extent;
1270: Query query;
1271: String filter;
1272: Collection collection;
1273: Land land;
1274: Point3d center;
1275:
1276: try {
1277: transaction = this .getPersistenceManager()
1278: .currentTransaction();
1279: transaction.begin();
1280:
1281: extent = this .getPersistenceManager().getExtent(Land.class,
1282: true);
1283: filter = new String(
1284: "SELECT Land FROM Land l WHERE l.getUserOwner()==this");
1285: query = this .getPersistenceManager().newQuery(Land.class,
1286: extent, filter);
1287: collection = (Collection) query.execute();
1288:
1289: transaction.commit();
1290:
1291: if (collection.size() > 0) {
1292: //collection
1293: land = (Land) collection.iterator().next();
1294: this .homePosition = new Transform3D();
1295: center = new Point3d();
1296: new BoundingSphere(land.getBounds()).getCenter(center);
1297: this .homePosition.set(new Vector3d(center));
1298: }
1299:
1300: } catch (Exception exception) {
1301: }
1302:
1303: }
1304:
1305: private final boolean checkHome(Transform3D homePosition) {
1306:
1307: Transform3D oldTransform3D;
1308: Point3d point3d;
1309: Transaction transaction;
1310: Extent extent;
1311: Query query;
1312: String filter;
1313: Collection collection;
1314: HashSet result;
1315:
1316: point3d = new Point3d();
1317: homePosition.transform(point3d);
1318:
1319: try {
1320: transaction = this .getPersistenceManager()
1321: .currentTransaction();
1322: transaction.begin();
1323:
1324: extent = this .getPersistenceManager().getExtent(Land.class,
1325: true);
1326: filter = new String(
1327: "SELECT Land FROM Land l WHERE l.getBounds().intersect(point3d)");
1328: query = this .getPersistenceManager().newQuery(Land.class,
1329: extent, filter);
1330: collection = (Collection) query.execute();
1331:
1332: transaction.commit();
1333: result = this .filterCollection(this , collection);
1334:
1335: return (result.size() > 0);
1336:
1337: } catch (Exception exception) {
1338:
1339: return false;
1340:
1341: }
1342:
1343: }
1344:
1345: public final Skin getSkin() {
1346:
1347: return this .skin;
1348:
1349: }
1350:
1351: //skin owner should be the same as this owner
1352: public final void setSkin(Skin skin) {
1353:
1354: if ((skin != null) && (skin.getUserOwner() == this )) {
1355: this .skin = skin;
1356: }
1357:
1358: }
1359:
1360: public final HashSet getInventory() {
1361:
1362: return this .inventory;
1363:
1364: }
1365:
1366: //objectWorld should not be bound to another user's inventory but this is checked
1367: //can add weared skins but it is not recommended because some avatar is going to be invisible
1368: //object must be owned by user
1369: //capabilities must be set to ObjectWorld.VISIBLE
1370: //capabilities must be set to ObjectWorld.MOVABLE, ObjectWorld.SONORE
1371: //capabilities must be set to ObjectWorld.INVENTORIZABLE (system wide check)
1372: public final void addInventoryEntry(ObjectWorld objectWorld) {
1373:
1374: Transaction transaction;
1375: Extent extent;
1376: Query query;
1377: String filter;
1378: Collection collection;
1379:
1380: if ((objectWorld != null)
1381: && (objectWorld.getUserOwner() == this )) {
1382: try {
1383: transaction = this .getPersistenceManager()
1384: .currentTransaction();
1385: transaction.begin();
1386:
1387: extent = this .getPersistenceManager().getExtent(
1388: Avatar.class, true);
1389: filter = new String(
1390: "SELECT Avatar FROM Avatar a WHERE a.getInventory().contains(objectWorld)");
1391: query = this .getPersistenceManager().newQuery(
1392: Avatar.class, extent, filter);
1393: collection = (Collection) query.execute();
1394:
1395: transaction.commit();
1396:
1397: //there should be at most one avatar
1398: if (collection.size() == 0) {
1399: if (objectWorld
1400: .checkWritable(ObjectWorld.INVENTORIZABLE
1401: + ObjectWorld.VISIBLE
1402: + ObjectWorld.SONORE
1403: + ObjectWorld.MOVABLE)) {
1404: this .inventory.add(objectWorld);
1405: objectWorld.setInvisible();
1406: objectWorld.setUnSonore();
1407: objectWorld.doInventorize(this );
1408: }
1409: }
1410:
1411: } catch (Exception exception) {
1412: }
1413:
1414: }
1415:
1416: }
1417:
1418: private void removeAllInventoryEntries() {
1419:
1420: Iterator iterator;
1421:
1422: iterator = this .inventory.iterator();
1423: while (iterator.hasNext()) {
1424: this .removeInventoryEntry((ObjectWorld) iterator.next());
1425: }
1426:
1427: }
1428:
1429: //objectWorld should pop out of user's pocket where he is
1430: public final void removeInventoryEntry(ObjectWorld objectWorld) {
1431:
1432: if (this .inventory.contains(objectWorld)) {
1433: this .inventory.remove(objectWorld);
1434: objectWorld.doUnInventorize();
1435: objectWorld.setVisible();
1436: objectWorld.setSonore();
1437: }
1438:
1439: }
1440:
1441: //In a big community, lords will probably be notified about many vassals actions (requests from their vassals to access land...). This should rapidly create an
1442: //unwanted network overload as well as a lot of unwanted junk data. A filter mechanism is proposed in which users can decide not to be notified when a
1443: //vassal makes a request (the notification message is not send from the server). The filter is a list of pairs key-key value.
1444: //The key mentions the Object concerned and the kind of request:
1445: // Request field read - field write (of an object, tool, guide, avatar, land, World Spot)
1446: // Request action execution (of an object, tool, guide, avatar, land, World Spot), the action may involve creation, modification or deletion of an object,
1447: // tool, guide, avatar, land.
1448: //The key-value is given with 6 booleans to grant notification about users' actions for the owner himself, lords, invited lords, peers, peers vassals and vassals.
1449: //Using the notification filter, users can choose not to see or hear or collide from objects, tools, guides, avatars, owners (corresponding fields in the avatar).
1450: //Users that make no filtering will have a log of every actions about themselves, lords, invited lords, peers, peers vassals and vassals. Since lords can also
1451: //decide to refuse to be queried, this log can be incomplete. The only complete log is the one of the top lord if he requests no filtering.
1452: //
1453: //the notification filter mentions positive notification
1454: //users are notified of nothing (except answers to their requests) if they do not request anything
1455: //if a user want to be notified of a lord visiting one of its lands then he has to add en entry in the notification filter
1456:
1457: //filter list is valid if its elements refer to different accessKind for every object
1458: //originator for the filters must correspond to this user
1459: public final Collection getFilters() {
1460:
1461: Transaction transaction;
1462: Extent extent;
1463: Query query;
1464: String filter;
1465: Collection collection;
1466:
1467: try {
1468: transaction = this .getPersistenceManager()
1469: .currentTransaction();
1470: transaction.begin();
1471:
1472: extent = this .getPersistenceManager().getExtent(
1473: Filter.class, true);
1474: filter = new String(
1475: "SELECT Filter FROM Filter f WHERE f.getRequester()==this");
1476: query = this .getPersistenceManager().newQuery(Filter.class,
1477: extent, filter);
1478: collection = (Collection) query.execute();
1479:
1480: transaction.commit();
1481:
1482: return collection;
1483:
1484: } catch (Exception exception) {
1485:
1486: return null;
1487:
1488: }
1489:
1490: }
1491:
1492: public final void addFilter(Filter filter) {
1493:
1494: Transaction transaction;
1495:
1496: if ((filter != null) && (filter.getRequester() == this )) {
1497:
1498: try {
1499: transaction = this .getPersistenceManager()
1500: .currentTransaction();
1501: transaction.begin();
1502:
1503: this .getPersistenceManager().makePersistent(filter);
1504:
1505: transaction.commit();
1506: } catch (Exception exception) {
1507: }
1508:
1509: }
1510:
1511: }
1512:
1513: private final void removeAllFilters() {
1514:
1515: Transaction transaction;
1516:
1517: try {
1518: transaction = this .getPersistenceManager()
1519: .currentTransaction();
1520: transaction.begin();
1521:
1522: this .getPersistenceManager().deletePersistentAll(
1523: this .getFilters());
1524:
1525: transaction.commit();
1526: } catch (Exception exception) {
1527: }
1528:
1529: }
1530:
1531: public final void removeFilter(Filter filter) {
1532:
1533: Transaction transaction;
1534:
1535: try {
1536: transaction = this .getPersistenceManager()
1537: .currentTransaction();
1538: transaction.begin();
1539:
1540: this .getPersistenceManager().deletePersistent(filter);
1541:
1542: transaction.commit();
1543: } catch (Exception exception) {
1544: }
1545:
1546: }
1547:
1548: public final Collection getBlockers() {
1549:
1550: Transaction transaction;
1551: Extent extent;
1552: Query query;
1553: String filter;
1554: Collection collection;
1555:
1556: try {
1557: transaction = this .getPersistenceManager()
1558: .currentTransaction();
1559: transaction.begin();
1560:
1561: // Execute a query
1562: extent = this .getPersistenceManager().getExtent(
1563: Blocker.class, true);
1564: filter = new String(
1565: "SELECT Blocker FROM Blocker b WHERE b.getRequester()==this");
1566: query = this .getPersistenceManager().newQuery(
1567: Blocker.class, extent, filter);
1568: collection = (Collection) query.execute();
1569:
1570: transaction.commit();
1571:
1572: return collection;
1573:
1574: } catch (Exception exception) {
1575:
1576: return null;
1577:
1578: }
1579:
1580: }
1581:
1582: //When a user doesn't want some automatic requests he sends to be completed
1583: //for example if you want no to see anymore some kind of geometry that prevents easy movements in an are
1584: //and provided you have the rights to do so, you can put a blocker in your avatar's blocker list to filter the
1585: //automatic queries send to the server and therefore you won't hear or see from that object
1586: //be aware that this is a way of reducing your capabilities in the virtual world
1587: //if you prevent requests to be completed by putting a blocker you may be able to cut yourself access to the virtual world
1588: //In that case, ask a super user to remove the faulty blockers by first building a new account or sending an e-mail.
1589: //(list of faulty blockers is only checked about user ownership)
1590:
1591: //a blocker is a kind of filter
1592: //originator for the blockers must correspond to this user
1593: //blocked object can't be owned by this avatar or be the avatar itself
1594: public final void addBlocker(Blocker blocker) {
1595:
1596: Transaction transaction;
1597:
1598: if ((blocker != null) && (blocker.getRequester() == this )) {
1599: if (blocker.getObject() instanceof Avatar) {
1600: if (((Avatar) blocker.getObject()) != this ) {
1601: try {
1602: transaction = this .getPersistenceManager()
1603: .currentTransaction();
1604: transaction.begin();
1605:
1606: this .getPersistenceManager().makePersistent(
1607: blocker);
1608:
1609: transaction.commit();
1610: } catch (Exception exception) {
1611: }
1612: }
1613: } else {
1614: if (blocker.getObject() instanceof VirtualElement) {
1615: if (((VirtualElement) blocker.getObject())
1616: .getUserOwner() != this ) {
1617: try {
1618: transaction = this .getPersistenceManager()
1619: .currentTransaction();
1620: transaction.begin();
1621:
1622: this .getPersistenceManager()
1623: .makePersistent(blocker);
1624:
1625: transaction.commit();
1626: } catch (Exception exception) {
1627: }
1628:
1629: }
1630: }
1631: }
1632: }
1633:
1634: }
1635:
1636: public final void removeBlocker(Blocker blocker) {
1637:
1638: Transaction transaction;
1639:
1640: try {
1641: transaction = this .getPersistenceManager()
1642: .currentTransaction();
1643: transaction.begin();
1644:
1645: this .getPersistenceManager().deletePersistent(blocker);
1646:
1647: transaction.commit();
1648: } catch (Exception exception) {
1649: }
1650:
1651: }
1652:
1653: private final void removeAllBlockers() {
1654:
1655: Transaction transaction;
1656:
1657: try {
1658: transaction = this .getPersistenceManager()
1659: .currentTransaction();
1660: transaction.begin();
1661:
1662: this .getPersistenceManager().deletePersistentAll(
1663: this .getBlockers());
1664:
1665: transaction.commit();
1666: } catch (Exception exception) {
1667: }
1668:
1669: }
1670:
1671: public final boolean getVassalsAccountCreation() {
1672:
1673: return this .vassalsMayCreateAccounts;
1674:
1675: }
1676:
1677: //setting this parameter does not prevent a lord to refuse user creation
1678: public final void setVassalsAccountCreation(
1679: boolean vassalsMayCreateAccounts) {
1680:
1681: this .vassalsMayCreateAccounts = vassalsMayCreateAccounts;
1682:
1683: }
1684:
1685: //SYSTEM CALLS
1686:
1687: public final static WorldSpot getWorldSpot(Avatar avatar) {
1688:
1689: Skin skin;
1690: Transform3D transform3D;
1691: Point3d point3d;
1692: Transaction transaction;
1693: Extent extent;
1694: Query query;
1695: String filter;
1696: Collection collection;
1697:
1698: if (avatar != null) {
1699: skin = avatar.getSkin();
1700: transform3D = skin.getTransform3D();
1701: point3d = new Point3d();
1702: transform3D.transform(point3d);
1703:
1704: try {
1705: transaction = avatar.getPersistenceManager()
1706: .currentTransaction();
1707: transaction.begin();
1708:
1709: extent = avatar.getPersistenceManager().getExtent(
1710: WorldSpot.class, true);
1711: filter = new String(
1712: "SELECT WorldSpot FROM WorldSpot w WHERE w.getBounds().intersect(point3d)");
1713: query = avatar.getPersistenceManager().newQuery(
1714: WorldSpot.class, extent, filter);
1715: collection = (Collection) query.execute();
1716:
1717: transaction.commit();
1718:
1719: //each avatar should be in exactly one worldSpot at a time
1720: return (WorldSpot) (collection.iterator().next());
1721:
1722: } catch (Exception exception) {
1723:
1724: return null;
1725:
1726: }
1727:
1728: } else {
1729: return null;
1730: }
1731:
1732: }
1733:
1734: //recursively get all vassals
1735: //equivalent to a query with "SELECT Avatar FROM Avatar a WHERE Avatar.getFeudalRelation(a, this)=Avatar.VASSAL;
1736: //but much faster
1737: public final HashSet getAllVassals() {
1738:
1739: return Avatar.getWorldSpot(this ).getAllVassals(this );
1740:
1741: }
1742:
1743: //returns the land the avatar is currently on
1744: //this land should be navigable for this user
1745: public final Land getCurrentLand(Avatar avatar) {
1746:
1747: Skin skin;
1748: Transform3D transform3D;
1749: Point3d point3d;
1750: Transaction transaction;
1751: Extent extent;
1752: Query query;
1753: String filter;
1754: Collection collection;
1755: HashSet result;
1756:
1757: if ((avatar != null) && (avatar.getSkin() != null)) {
1758: skin = avatar.getSkin();
1759: transform3D = skin.getTransform3D();
1760: point3d = new Point3d();
1761: transform3D.transform(point3d);
1762:
1763: try {
1764: transaction = this .getPersistenceManager()
1765: .currentTransaction();
1766: transaction.begin();
1767:
1768: extent = this .getPersistenceManager().getExtent(
1769: Land.class, true);
1770: filter = new String(
1771: "SELECT Land FROM Land l WHERE l.getBounds().intersect(point3d)");
1772: query = this .getPersistenceManager().newQuery(
1773: Land.class, extent, filter);
1774: collection = (Collection) query.execute();
1775:
1776: transaction.commit();
1777:
1778: result = this .filterCollection(avatar, collection);
1779: if (result.size() > 0) {
1780: //each avatar should be in exactly one land at a time
1781: return (Land) (result.iterator().next());
1782: } else {
1783: return null;
1784: }
1785:
1786: } catch (Exception exception) {
1787:
1788: return null;
1789:
1790: }
1791:
1792: } else {
1793: return null;
1794: }
1795:
1796: }
1797:
1798: //returns null if the Avatar is already Avatar.Ruler
1799: //could also be called getParent(Avatar avatar)
1800: //please note this is a very computer intensive call
1801: protected final static Avatar getLord(Avatar avatar) {
1802:
1803: Transaction transaction;
1804: Extent extent;
1805: Query query;
1806: String filter;
1807: Collection collection;
1808:
1809: if (avatar != null) {
1810: try {
1811: transaction = avatar.getPersistenceManager()
1812: .currentTransaction();
1813: transaction.begin();
1814:
1815: extent = avatar.getPersistenceManager().getExtent(
1816: Avatar.class, true);
1817: filter = new String(
1818: "SELECT Avatar FROM Avatar a WHERE a.getVassal().contains(avatar)");
1819: query = avatar.getPersistenceManager().newQuery(
1820: Avatar.class, extent, filter);
1821: collection = (Collection) query.execute();
1822:
1823: transaction.commit();
1824:
1825: if (collection.size() == 0) {
1826: //avatar has no parent therefore it must be a ruler
1827: return null;
1828: } else {
1829: //every other avatar has exactely one parent
1830: return (Avatar) collection.iterator().next();
1831: }
1832:
1833: } catch (Exception exception) {
1834:
1835: return null;
1836:
1837: }
1838:
1839: } else {
1840: return null;
1841: }
1842:
1843: }
1844:
1845: //lords are returned from the top lord in decreasing order
1846: //last of the list is the avatar himself (which is its own lord)
1847: protected final static Vector getLords(Avatar avatar) {
1848: //it is probably faster to get the ruler, build a tree from top to bottom until avatar is reached and
1849: //get the direct list out of it
1850:
1851: WorldSpot worldSpot;
1852: Avatar currentAvatar;
1853: HashSet currentPawns;
1854: HashSet currentVassals;
1855: Tree topTree;
1856: Tree currentTree;
1857: Tree[] treeElements;
1858: Vector treeLevel;
1859: boolean found;
1860: int i;
1861: Vector vector1;
1862: Vector vector2;
1863: Iterator iterator;
1864:
1865: if (avatar != null) {
1866:
1867: worldSpot = avatar.getWorldSpot(avatar);
1868: currentAvatar = worldSpot.getRuler();
1869: topTree = new Tree(currentAvatar);
1870:
1871: //build the tree of avatars
1872: //avatar is belived to exist somewhere in the hierarchy
1873:
1874: treeElements = new Tree[1];
1875: treeElements[0] = topTree;
1876:
1877: found = ((Avatar) topTree.getElement()) == avatar;
1878:
1879: while (!found) {
1880:
1881: for (i = 0; i < treeElements.length; i++) {
1882:
1883: avatar = (Avatar) treeElements[i].getElement();
1884: treeLevel = new Vector();
1885:
1886: currentPawns = avatar.getPawns();
1887: currentVassals = avatar.getVassals();
1888:
1889: iterator = currentPawns.iterator();
1890: for (i = 0; i < currentPawns.size(); i++) {
1891: currentTree = new Tree(iterator.next());
1892: try {
1893: treeElements[i].addChild(currentTree);
1894: } catch (CyclicTreeException cyclicTreeException) {
1895: }
1896: treeLevel.add(currentTree);
1897: found = (found || (((Avatar) currentTree
1898: .getElement()) == avatar));
1899: }
1900:
1901: iterator = currentVassals.iterator();
1902: for (i = 0; i < currentVassals.size(); i++) {
1903: currentTree = new Tree(iterator.next());
1904: try {
1905: treeElements[i].addChild(currentTree);
1906: } catch (CyclicTreeException cyclicTreeException) {
1907: }
1908: treeLevel.add(currentTree);
1909: found = (found || (((Avatar) currentTree
1910: .getElement()) == avatar));
1911: }
1912:
1913: treeElements = (Tree[]) treeLevel.toArray();
1914: }
1915: }
1916:
1917: //find the avatar in the tree
1918: i = 0;
1919: found = false;
1920: while (i < treeElements.length && (!found)) {
1921: found = ((Avatar) treeElements[i].getElement()) == avatar;
1922: i++;
1923: }
1924:
1925: //build the resulting vector
1926: vector1 = new Vector();
1927: currentTree = treeElements[i - 1];
1928: while (currentTree != null) {
1929: vector1.add(currentTree.getElement());
1930: currentTree = currentTree.getParent();
1931: }
1932:
1933: //return the Vector
1934: vector2 = new Vector();
1935: for (i = vector1.size() - 1; i >= 0; i--) {
1936: vector2.add(vector1.elementAt(i));
1937: }
1938:
1939: return vector2;
1940:
1941: } else {
1942: return null;
1943: }
1944:
1945: }
1946:
1947: //given Avatar1 and Avatar2 (which SHOULD NOT BE null) this method returns the nearest common lord of both users
1948: protected final static Avatar getCommonLord(Avatar avatar1,
1949: Avatar avatar2) {
1950:
1951: Vector vector1;
1952: Vector vector2;
1953: int i;
1954: boolean found;
1955:
1956: if ((avatar1 != null) && (avatar2 != null)) {
1957: vector1 = Avatar.getLords(avatar1);
1958: vector2 = Avatar.getLords(avatar2);
1959:
1960: if (vector1.get(0) != vector2.get(0)) {
1961: return null;
1962: } else {
1963:
1964: i = 0;
1965: found = false;
1966: while ((i < Math.min(vector1.size(), vector2.size()))
1967: && (found)) {
1968: found = (vector1.get(i) == vector2.get(i));
1969: i++;
1970: }
1971: return (Avatar) vector1.get(i - 1);
1972: }
1973:
1974: } else {
1975: return null;
1976: }
1977:
1978: }
1979:
1980: //avatars should be at least of length 1
1981: protected final static Avatar getCommonLord(Avatar[] avatars) {
1982:
1983: Vector[] vectors;
1984: int i;
1985: boolean found;
1986: int minimum;
1987: int j;
1988: boolean good;
1989:
1990: if (avatars != null) {
1991:
1992: vectors = new Vector[avatars.length];
1993:
1994: for (i = 0; i < avatars.length; i++) {
1995: vectors[i] = Avatar.getLords(avatars[i]);
1996: }
1997:
1998: i = 0;
1999: found = false;
2000: while ((i < avatars.length) && (!found)) {
2001: found = (vectors[0].get(0) != vectors[i].get(0));
2002: i++;
2003: }
2004:
2005: if (found) {
2006: return null;
2007: } else {
2008:
2009: i = 0;
2010: minimum = vectors[0].size();
2011: while (i < avatars.length) {
2012: minimum = Math.min(minimum, vectors[i].size());
2013: i++;
2014: }
2015:
2016: i = 0;
2017: found = false;
2018: while ((i < minimum) && (found)) {
2019: j = 0;
2020: good = true;
2021: while ((j < avatars.length) && (good)) {
2022: good = (vectors[0].get(i) == vectors[j].get(i));
2023: j++;
2024: }
2025: found = (good && (j == avatars.length));
2026: i++;
2027: }
2028: return (Avatar) vectors[0].get(i - 1);
2029: }
2030:
2031: } else {
2032: return null;
2033: }
2034:
2035: }
2036:
2037: //it is assumed that avatars are on the same worldSpot otherwise Avatar.NONE is returned
2038: // avatar1 is the Avatar.XXXX of avatar2
2039: public final static int getFeudalRelation(Avatar avatar1,
2040: Avatar avatar2) {
2041:
2042: Vector vector1;
2043: Vector vector2;
2044:
2045: if ((avatar1 != null) && (avatar2 != null)) {
2046:
2047: if (avatar1 == avatar2) {
2048: return Avatar.SELF;
2049: } else {
2050:
2051: vector1 = Avatar.getLords(avatar1);
2052: vector2 = Avatar.getLords(avatar2);
2053:
2054: //vectors are at least of length 1
2055: if (vector1.get(0) != vector2.get(0)) {
2056: return Avatar.NONE;
2057: } else {
2058:
2059: if (vector1.size() == vector2.size()) {
2060: return Avatar.PEER;
2061: } else {
2062: if (vector1.size() > vector2.size()) {
2063: if (vector2.lastElement() == vector1
2064: .get(vector2.size() - 1)) {
2065: return Avatar.VASSAL;
2066: } else {
2067: return Avatar.PEERSVASSAL;
2068: }
2069: } else {//vector1.size()<vector2.size()
2070:
2071: if (vector1.lastElement() == vector2
2072: .get(vector1.size() - 1)) {
2073: return Avatar.LORD;
2074: } else {
2075: return Avatar.PEERSLORD;
2076: }
2077: }
2078: }
2079: }
2080: }
2081:
2082: } else {
2083: return Avatar.NONE;
2084: }
2085:
2086: }
2087:
2088: //equivalent but not implemented as avatar.getlord()==null
2089: public static final boolean isRuler(Avatar avatar) {
2090:
2091: Transaction transaction;
2092: Extent extent;
2093: Query query;
2094: String filter;
2095: Collection collection;
2096:
2097: if (avatar != null) {
2098:
2099: try {
2100: transaction = avatar.getPersistenceManager()
2101: .currentTransaction();
2102: transaction.begin();
2103:
2104: extent = avatar.getPersistenceManager().getExtent(
2105: Avatar.class, true);
2106: filter = new String(
2107: "SELECT WorldSpot FROM WorldSpot w WHERE w.getRuler()==avatar");
2108: query = avatar.getPersistenceManager().newQuery(
2109: Avatar.class, extent, filter);
2110: collection = (Collection) query.execute();
2111:
2112: transaction.commit();
2113:
2114: return collection.contains(avatar);
2115:
2116: } catch (Exception exception) {
2117:
2118: return false;
2119:
2120: }
2121:
2122: } else {
2123: return false;
2124: }
2125:
2126: }
2127:
2128: //this call assumes valid user's rights (depending on who calls)
2129: //otherwise the server returns a request refused message
2130:
2131: //called by avatar at will and at creation time to be sure the login isn't reserved
2132: //synchronisation should be done while effectively creating the new avatar
2133: public final boolean checkLoginAndPasswordExists(
2134: LoginInformation loginInformation) {
2135:
2136: Transaction transaction;
2137: Extent extent;
2138: Query query;
2139: String filter;
2140: Collection collection;
2141:
2142: //checks against all users login stored in database
2143: try {
2144: transaction = this .getPersistenceManager()
2145: .currentTransaction();
2146: transaction.begin();
2147:
2148: extent = this .getPersistenceManager().getExtent(
2149: Avatar.class, true);
2150: filter = new String(
2151: "SELECT Avatar FROM Avatar a WHERE a.getLoginInformation().checkLoginAndPassword(loginInformation)==true");
2152: query = this .getPersistenceManager().newQuery(Avatar.class,
2153: extent, filter);
2154: collection = (Collection) query.execute();
2155:
2156: transaction.commit();
2157:
2158: return (collection.size() != 0);
2159:
2160: } catch (Exception exception) {
2161:
2162: return false;
2163:
2164: }
2165:
2166: }
2167:
2168: public final Avatar findAvatar(LoginInformation loginInformation) {
2169:
2170: Transaction transaction;
2171: Extent extent;
2172: Query query;
2173: String filter;
2174: Collection collection;
2175:
2176: //checks against all users login stored in database
2177: try {
2178: transaction = this .getPersistenceManager()
2179: .currentTransaction();
2180: transaction.begin();
2181:
2182: extent = this .getPersistenceManager().getExtent(
2183: Avatar.class, true);
2184: filter = new String(
2185: "SELECT Avatar FROM Avatar a WHERE a.getLoginInformation().checkLoginAndPassword(loginInformation)==true");
2186: query = this .getPersistenceManager().newQuery(Avatar.class,
2187: extent, filter);
2188: collection = (Collection) query.execute();
2189:
2190: transaction.commit();
2191:
2192: if (collection.size() != 0) {
2193: //there should be at most one avatar
2194: return (Avatar) collection.iterator().next();
2195: } else {
2196: return null;
2197: }
2198:
2199: } catch (Exception exception) {
2200:
2201: return null;
2202:
2203: }
2204:
2205: }
2206:
2207: //valid only for non rulers (ie: parent may not be null)
2208: //returns null if avatar can't be created
2209: protected final static Avatar createUserAccount(
2210: LoginInformation loginInformation, Avatar parent) {
2211:
2212: Transaction transaction;
2213: Avatar avatar;
2214: Vector avatars;
2215: int i;
2216: boolean found;
2217:
2218: if (parent != null) {
2219:
2220: synchronized (parent) {
2221: //all lords must agree account creation
2222: avatars = Avatar.getLords(parent);
2223:
2224: found = false;
2225: i = 0;
2226: while ((i < avatars.size()) && (found)) {
2227: found = ((Avatar) avatars.get(i))
2228: .getVassalsAccountCreation();
2229: i++;
2230: }
2231: if (!found) {
2232: if (!parent
2233: .checkLoginAndPasswordExists(loginInformation)) {
2234: avatar = new Avatar(parent.getUniverseServer(),
2235: loginInformation);
2236:
2237: try {
2238: transaction = parent
2239: .getPersistenceManager()
2240: .currentTransaction();
2241: transaction.begin();
2242:
2243: parent.getPersistenceManager()
2244: .makePersistent(avatar);
2245:
2246: transaction.commit();
2247: } catch (Exception exception) {
2248: }
2249:
2250: //please also give a skin and a land to this avatar
2251: //this also of navigation, information and socialization tools
2252:
2253: //lands = parent.getLands();
2254: //lands[0].split(XXX);
2255: //avatar.addLand(XXX);
2256: //avatar.setHomePosition(XXX);
2257: //avatar.setSkin(XXX);
2258: //skin.setTransform3D(this.getHomePosition());
2259: //avatar.addInventoryEntry(XXX);
2260:
2261: //this.createHome();
2262:
2263: parent.createVassal(avatar);
2264:
2265: } else {
2266: avatar = null;
2267: }
2268: } else {
2269: avatar = null;
2270: }
2271: }
2272: } else {
2273: avatar = null;
2274: }
2275:
2276: return avatar;
2277:
2278: }
2279:
2280: //does also work for self to reparent to someone else
2281: //capabilities must be set accordingly
2282: //if newParent is a vassal or a pawn of avatar then its vassals are reparented to avatar's lord
2283: //if not, every vassal and pawn is moved along with avatar and therefore keep its parental relationship with avatar
2284: //rulers can be reparented if they have one only child
2285: //you can't reparent to yourself
2286: //moveUserInHierarchy(this,this.getLord()) is a null operation
2287: //to reparent an avatar as a ruler moveUserInHierarchy(avatar, null);
2288: protected final static void moveUserInHierarchy(Avatar avatar,
2289: Avatar newParent) {
2290:
2291: Avatar oldRuler;
2292: Avatar vassal;
2293:
2294: if (avatar != null) {
2295:
2296: if ((newParent != null) && (avatar != newParent)) {
2297:
2298: oldRuler = Avatar.getWorldSpot(avatar).getRuler();
2299: if ((newParent == null)
2300: && (oldRuler.getVassals().size() == 1)
2301: && (avatar != oldRuler)) {
2302: //avatar becomes new ruler
2303: synchronized (avatar) {
2304: Avatar.getLord(avatar).killVassal(avatar);
2305: avatar.createVassal(oldRuler);
2306: avatar.updateAccount();
2307: }
2308: } else {
2309: if ((oldRuler == avatar)
2310: && (avatar.getVassals().size() == 1)
2311: && (newParent != null)) {
2312: //Ruler avatar is moved down in the hierarchy
2313: synchronized (avatar) {
2314: vassal = (Avatar) avatar.getVassals()
2315: .iterator().next();
2316: Avatar.getWorldSpot(avatar)
2317: .setRuler(vassal);
2318: avatar.killVassal(vassal);
2319: newParent.createVassal(avatar);
2320: avatar.updateAccount();
2321: }
2322: } else {
2323: if (newParent != null) {
2324: //avatar is normally reparented
2325: synchronized (avatar) {
2326: Avatar.getLord(avatar).killVassal(
2327: avatar);
2328: newParent.createVassal(avatar);
2329: avatar.updateAccount();
2330: }
2331:
2332: }
2333:
2334: }
2335:
2336: }
2337:
2338: }
2339:
2340: }
2341:
2342: }
2343:
2344: //agreeingParent must be a lord of avatar and of new parent
2345: public final static void moveUserInHierarchy(Avatar avatar,
2346: Avatar newParent, Avatar agreeingParent) {
2347:
2348: if ((avatar != null) && (newParent != null)
2349: && (agreeingParent != null)) {
2350: if ((Avatar.getLords(avatar).contains(agreeingParent))
2351: && (Avatar.getLords(newParent)
2352: .contains(agreeingParent))) {
2353: Avatar.moveUserInHierarchy(avatar, newParent);
2354: }
2355: }
2356:
2357: }
2358:
2359: //updates position, inventory, skin, possessions (backgoundWorlds, objectWorlds),
2360: //lands access for others objectWorlds, backgroundWorlds and avatars
2361: protected final void updateAccount() {
2362:
2363: Transaction transaction;
2364: Extent extent;
2365: Query query;
2366: String filter;
2367: Collection collection;
2368: ObjectWorld objectWorld;
2369: BackgroundWorld backgroundWorld;
2370: Land land;
2371: Iterator iterator;
2372:
2373: if (this .getHomePosition() == null) {
2374: this .createHome();
2375: }
2376:
2377: //checks against all users login stored in database
2378: try {
2379: transaction = this .getPersistenceManager()
2380: .currentTransaction();
2381: transaction.begin();
2382:
2383: extent = this .getPersistenceManager().getExtent(
2384: Avatar.class, true);
2385: filter = new String(
2386: "SELECT * FROM ObjectWorld o WHERE o.getUserOwner()==this");
2387: query = this .getPersistenceManager().newQuery(Avatar.class,
2388: extent, filter);
2389: collection = (Collection) query.execute();
2390:
2391: transaction.commit();
2392:
2393: iterator = collection.iterator();
2394: while (iterator.hasNext()) {
2395: objectWorld = (ObjectWorld) iterator.next();
2396: objectWorld.refreshTransform();
2397: }
2398:
2399: } catch (Exception exception) {
2400: }
2401:
2402: try {
2403: transaction = this .getPersistenceManager()
2404: .currentTransaction();
2405: transaction.begin();
2406:
2407: extent = this .getPersistenceManager().getExtent(
2408: Avatar.class, true);
2409: filter = new String(
2410: "SELECT * FROM BackgroundWorld b WHERE b.getUserOwner()==this");
2411: query = this .getPersistenceManager().newQuery(Avatar.class,
2412: extent, filter);
2413: collection = (Collection) query.execute();
2414:
2415: transaction.commit();
2416:
2417: iterator = collection.iterator();
2418: while (iterator.hasNext()) {
2419: backgroundWorld = (BackgroundWorld) iterator.next();
2420: backgroundWorld.refreshBounds();
2421: }
2422:
2423: } catch (Exception exception) {
2424: }
2425:
2426: try {
2427: transaction = this .getPersistenceManager()
2428: .currentTransaction();
2429: transaction.begin();
2430:
2431: extent = this .getPersistenceManager().getExtent(
2432: Avatar.class, true);
2433: filter = new String(
2434: "SELECT * FROM Land l WHERE l.getUserOwner()==this");
2435: query = this .getPersistenceManager().newQuery(Avatar.class,
2436: extent, filter);
2437: collection = (Collection) query.execute();
2438:
2439: transaction.commit();
2440:
2441: iterator = collection.iterator();
2442: while (iterator.hasNext()) {
2443: land = (Land) iterator.next();
2444: land.refreshContents();
2445: }
2446:
2447: } catch (Exception exception) {
2448: }
2449:
2450: }
2451:
2452: //delete user account (actually release database resources)
2453: //pass, tickets and receipts should be deleted at this step
2454: //pool of avatar's belonging should be emptied of avatar's belongings for this command to succeed
2455: //cannot delete ruler
2456: //you have to pawn user before deleting account
2457: //boolean returns success or failure (avatar still exists)
2458: protected final static boolean deleteUserAccount(Avatar avatar) {
2459:
2460: Avatar lord;
2461: Transaction transaction;
2462: Extent extent;
2463: Query query;
2464: String filter;
2465: Collection collection;
2466: Iterator iterator;
2467: Pass pass1;
2468: Pass pass2;
2469: Vector vector;
2470: boolean success;
2471:
2472: success = false;
2473:
2474: if (avatar != null) {
2475:
2476: lord = Avatar.getLord(avatar);
2477:
2478: if (lord != null) {
2479: //verify this is a pawn
2480: if (avatar.getStatus() == Avatar.PAWN) {
2481: //verify every belonging has been removed or transfered
2482: //elements not drawn from pool are still with this owner
2483:
2484: synchronized (avatar) {
2485:
2486: try {
2487: transaction = avatar
2488: .getPersistenceManager()
2489: .currentTransaction();
2490: transaction.begin();
2491:
2492: extent = avatar.getPersistenceManager()
2493: .getExtent(VirtualElement.class,
2494: true);
2495: filter = new String(
2496: "SELECT VirtualElement FROM VirtualElement v WHERE v.getUserOwner()==avatar)");
2497: query = avatar.getPersistenceManager()
2498: .newQuery(VirtualElement.class,
2499: extent, filter);
2500: collection = (Collection) query.execute();
2501:
2502: transaction.commit();
2503:
2504: if (collection.size() == 0) {
2505:
2506: //pass, tickets and receipts should be deleted at this step
2507: avatar.removeAllPass();
2508:
2509: //reparent pass emited by avatar and still in use by others avatars
2510:
2511: try {
2512: transaction = avatar
2513: .getPersistenceManager()
2514: .currentTransaction();
2515: transaction.begin();
2516:
2517: extent = avatar
2518: .getPersistenceManager()
2519: .getExtent(Pass.class, true);
2520: filter = new String(
2521: "SELECT Pass FROM Pass p WHERE p.getSender()==avatar");
2522: query = avatar
2523: .getPersistenceManager()
2524: .newQuery(Pass.class,
2525: extent, filter);
2526: collection = (Collection) query
2527: .execute();
2528: transaction.commit();
2529:
2530: iterator = collection.iterator();
2531: vector = new Vector();
2532: while (iterator.hasNext()) {
2533: pass1 = (Pass) iterator.next();
2534: pass2 = new Pass(pass1
2535: .getName(), pass1
2536: .getStartDate(), pass1
2537: .getEndDate(), lord,
2538: pass1.getReceiver(),
2539: pass1.getObject());
2540: vector.add(pass2);
2541: }
2542:
2543: try {
2544: transaction = avatar
2545: .getPersistenceManager()
2546: .currentTransaction();
2547: transaction.begin();
2548:
2549: avatar
2550: .getPersistenceManager()
2551: .deletePersistentAll(
2552: collection
2553: .toArray());
2554: avatar
2555: .getPersistenceManager()
2556: .makePersistentAll(
2557: vector
2558: .toArray());
2559:
2560: transaction.commit();
2561: } catch (Exception exception) {
2562: }
2563:
2564: avatar.removeAllTicketOrReceipts();
2565:
2566: //collapse hierarchy (notify parents and vassals)
2567:
2568: iterator = avatar.getVassals()
2569: .iterator();
2570:
2571: while (iterator.hasNext()) {
2572: Avatar.moveUserInHierarchy(
2573: (Avatar) iterator
2574: .next(), lord);
2575: }
2576:
2577: lord.killVassal(avatar);
2578:
2579: try {
2580: transaction = avatar
2581: .getPersistenceManager()
2582: .currentTransaction();
2583: transaction.begin();
2584:
2585: avatar.getPersistenceManager()
2586: .deletePersistent(
2587: avatar);
2588:
2589: transaction.commit();
2590: } catch (Exception exception) {
2591: }
2592:
2593: success = true;
2594:
2595: } catch (Exception exception) {
2596: }
2597:
2598: }
2599:
2600: } catch (Exception exception) {
2601: }
2602:
2603: }
2604:
2605: }
2606:
2607: }
2608:
2609: }
2610:
2611: return success;
2612:
2613: }
2614:
2615: //agreeingParent should be a lord of avatar
2616: public final static boolean deleteUserAccount(Avatar avatar,
2617: Avatar agreeingParent) {
2618:
2619: int relation;
2620:
2621: if ((avatar != null) && (agreeingParent != null)) {
2622: relation = Avatar.getFeudalRelation(avatar, agreeingParent);
2623: if ((relation == Avatar.LORD) || (relation == Avatar.SELF)) {
2624: return Avatar.deleteUserAccount(avatar);
2625: } else {
2626: return false;
2627: }
2628: } else {
2629: return false;
2630: }
2631:
2632: }
2633:
2634: private final static HashSet filterCollection(Avatar caller,
2635: Collection collection) {
2636:
2637: Iterator iterator;
2638: Iterator iterator2;
2639: Collection passCollection;
2640: HashSet resultCollection;
2641: int relation;
2642: VirtualElement virtualElement;
2643: boolean found;
2644: Pass pass;
2645:
2646: resultCollection = new HashSet();
2647:
2648: if (caller != null) {
2649:
2650: //objects with a pass may bypass access
2651: passCollection = caller.getPass();
2652:
2653: iterator = collection.iterator();
2654:
2655: while (iterator.hasNext()) {
2656:
2657: virtualElement = (VirtualElement) iterator.next();
2658: relation = Avatar.getFeudalRelation(caller,
2659: virtualElement.getUserOwner());
2660:
2661: if ((relation == Avatar.LORD)
2662: || (relation == Avatar.SELF)) {
2663: resultCollection.add(virtualElement);
2664: } else {
2665: if (virtualElement.getOthersAccessRights(relation) != VirtualElement.HIDDEN) {
2666: resultCollection.add(virtualElement);
2667: } else {
2668: iterator2 = passCollection.iterator();
2669: found = false;
2670: while (iterator2.hasNext() && (!found)) {
2671: pass = (Pass) iterator2.next();
2672: found = (pass.getObject() == virtualElement);
2673: }
2674: if (found) {
2675: resultCollection.add(virtualElement);
2676: }
2677: }
2678: }
2679:
2680: }
2681:
2682: }
2683:
2684: return resultCollection;
2685:
2686: }
2687:
2688: }
|