001: /*
002: * Copyright (c) 2001 Silvere Martin-Michiellot All Rights Reserved.
003: *
004: * Silvere Martin-Michiellot grants you ("Licensee") a non-exclusive,
005: * royalty free, license to use, modify and redistribute this
006: * software in source and binary code form,
007: * provided that i) this copyright notice and license appear on all copies of
008: * the software; and ii) Licensee does not utilize the software in a manner
009: * which is disparaging to Silvere Martin-Michiellot.
010: *
011: * This software is provided "AS IS," without a warranty of any kind. ALL
012: * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
013: * IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
014: * NON-INFRINGEMENT, ARE HEREBY EXCLUDED. Silvere Martin-Michiellot
015: * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES
016: * SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
017: * OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL
018: * Silvere Martin-Michiellot OR ITS LICENSORS BE LIABLE
019: * FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
020: * INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
021: * CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
022: * OR INABILITY TO USE SOFTWARE, EVEN IF Silvere Martin-Michiellot HAS BEEN
023: * ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
024: *
025: * This software is not designed or intended for use in on-line control of
026: * aircraft, air traffic, aircraft navigation or aircraft communications; or in
027: * the design, construction, operation or maintenance of any nuclear
028: * facility. Licensee represents and warrants that it will not use or
029: * redistribute the Software for such purposes.
030: *
031: * @Author: Silvere Martin-Michiellot
032: *
033: */
034:
035: package com.db.server;
036:
037: import com.sun.j3d.utils.scenegraph.io.*;
038: import java.io.Serializable;
039: import java.io.IOException;
040: import java.lang.IllegalArgumentException;
041: import java.security.PublicKey;
042: import java.util.*;
043: import javax.jdo.*;
044: import javax.media.j3d.*;
045: import javax.vecmath.*;
046:
047: /**
048: * the base class of all virtual world objects (this is mainly to provide a base class to the merchant system)
049: */
050: public abstract class VirtualElement extends Object implements
051: Serializable, SceneGraphIO, Cloneable {
052:
053: //Lords and self are always allowed full rights
054:
055: public final static int NO_CAPABILITY = 0;
056:
057: public final static int SALABLE = 1;
058:
059: private static int LAST_CAPABILITY = (VirtualElement.NO_CAPABILITY * 2) - 1;
060:
061: public static int DEFAULT_DESIGNER_CAPABILITIES = VirtualElement.LAST_CAPABILITY;
062:
063: //Lords and self are always allowed full rights
064:
065: public final static int HIDDEN = 0;
066: public final static int READ = 1;
067: public final static int READ_WRITE = 2;
068:
069: public final static String STRING_DATE = "Date";
070: public final static String STRING_AUTHOR_NAME = "Author Name";
071: public final static String STRING_AUTHOR_E_MAIL = "Author e-mail";
072: public final static String STRING_AUTHOR_PUBLIC_KEY = "Author Public Key";
073: public final static String STRING_NAME = "Name";
074: public final static String STRING_VERSION = "Version";
075:
076: //designer should set up a new value for the virtualElementCapabilities depending on its design choices
077: private final int virtualElementCapabilities = DEFAULT_DESIGNER_CAPABILITIES;
078: //rights to activate a behavior for the object depending on the triggering user
079: private final int[] othersAccessRights = { VirtualElement.READ,
080: VirtualElement.READ, VirtualElement.HIDDEN,
081: VirtualElement.READ };
082:
083: private UniverseServer universeServer;
084: private Avatar userOwner;
085: protected Hashtable information;
086: protected double price;
087: //currency defaults to Trade.US_DOLLAR
088: protected String currency;
089:
090: private Avatar caller;
091:
092: private boolean dirty;
093:
094: public VirtualElement() {
095:
096: throw new java.lang.IllegalArgumentException(
097: "A virtual element must have a persistenceManagerFactory and an owner.");
098:
099: }
100:
101: public VirtualElement(UniverseServer universeServer,
102: Avatar userOwner) {
103:
104: if ((universeServer != null) && (userOwner != null)) {
105: this .universeServer = universeServer;
106: this .userOwner = userOwner;
107: this .information = new Hashtable();
108: this .price = 0;
109: this .currency = Trade.US_DOLLAR;
110: this .dirty = false;
111: this .notifyFilterers(Filter.ADDITION, this );
112: } else {
113: throw new java.lang.IllegalArgumentException(
114: "A virtual element must have a valid universeServer and a valid owner.");
115: }
116:
117: }
118:
119: //every "get" or "set" call assumes valid user's rights (depending on who calls)
120: //otherwise the server returns a request refused message
121:
122: public final UniverseServer getUniverseServer() {
123:
124: return this .universeServer;
125:
126: }
127:
128: public final PersistenceManager getPersistenceManager() {
129:
130: return this .universeServer.getPersistenceManager();
131:
132: }
133:
134: protected final Avatar getCaller() {
135:
136: return this .caller;
137:
138: }
139:
140: protected final boolean getDirty() {
141:
142: return this .dirty;
143:
144: }
145:
146: protected final void setDirty() {
147:
148: this .dirty = true;
149:
150: }
151:
152: protected final void clearDirty() {
153:
154: this .dirty = false;
155:
156: }
157:
158: public final Avatar getUserOwner() {
159:
160: return this .userOwner;
161:
162: }
163:
164: public final Hashtable getInformation() {
165:
166: information.put(VirtualElement.STRING_DATE, this .getDate());
167: information.put(VirtualElement.STRING_AUTHOR_NAME, this
168: .getAuthorName());
169: information.put(VirtualElement.STRING_AUTHOR_E_MAIL, this
170: .getAuthorEMail());
171: information.put(VirtualElement.STRING_AUTHOR_PUBLIC_KEY, this
172: .getAuthorPublicKey());
173: information.put(VirtualElement.STRING_NAME, this .getName());
174: information.put(VirtualElement.STRING_VERSION, this
175: .getVersion());
176:
177: return information;
178:
179: }
180:
181: public final Object getInformation(String key) {
182:
183: information.put(VirtualElement.STRING_DATE, this .getDate());
184: information.put(VirtualElement.STRING_AUTHOR_NAME, this
185: .getAuthorName());
186: information.put(VirtualElement.STRING_AUTHOR_E_MAIL, this
187: .getAuthorEMail());
188: information.put(VirtualElement.STRING_AUTHOR_PUBLIC_KEY, this
189: .getAuthorPublicKey());
190: information.put(VirtualElement.STRING_NAME, this .getName());
191: information.put(VirtualElement.STRING_VERSION, this
192: .getVersion());
193:
194: return information.get(key);
195:
196: }
197:
198: public Date getDate() {
199:
200: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
201: //approximatively the date of the 1st January 2000
202: //return new Date(946728000L);
203: return (Date) information.get(VirtualElement.STRING_DATE);
204:
205: }
206:
207: public String getAuthorName() {
208:
209: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
210: //return new String("");
211: return (String) information
212: .get(VirtualElement.STRING_AUTHOR_NAME);
213:
214: }
215:
216: public String getAuthorEMail() {
217:
218: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
219: //return new String("");
220: return (String) information
221: .get(VirtualElement.STRING_AUTHOR_E_MAIL);
222:
223: }
224:
225: public PublicKey getAuthorPublicKey() {
226:
227: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
228: //return new byte[256];
229: return (PublicKey) information
230: .get(VirtualElement.STRING_AUTHOR_PUBLIC_KEY);
231:
232: }
233:
234: public String getName() {
235:
236: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
237: // return new String("");
238: return (String) information.get(VirtualElement.STRING_NAME);
239:
240: }
241:
242: public String getVersion() {
243:
244: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
245: //return new String("");
246: return (String) information.get(VirtualElement.STRING_VERSION);
247:
248: }
249:
250: public final double getPrice() {
251:
252: return this .price;
253:
254: }
255:
256: public final String getCurrency() {
257:
258: return this .currency;
259:
260: }
261:
262: public final void setUserOwner(Avatar userOwner) {
263:
264: this .userOwner = userOwner;
265: this .setDirty();
266: this .doUserOwnerChanged();
267:
268: }
269:
270: public final void setCaller(Avatar caller) {
271:
272: this .caller = caller;
273:
274: }
275:
276: public final void setDate(Date date) {
277:
278: information.put(VirtualElement.STRING_DATE, date);
279: this .setDirty();
280: this .doInformationChanged();
281:
282: }
283:
284: public final void setAuthorName(String name) {
285:
286: information.put(VirtualElement.STRING_AUTHOR_NAME, name);
287: this .setDirty();
288: this .doInformationChanged();
289:
290: }
291:
292: public final void setAuthorEMail(String eMail) {
293:
294: information.put(VirtualElement.STRING_AUTHOR_E_MAIL, eMail);
295: this .setDirty();
296: this .doInformationChanged();
297:
298: }
299:
300: public final void setAuthorPublicKey(PublicKey publicKey) {
301:
302: information.put(VirtualElement.STRING_AUTHOR_PUBLIC_KEY,
303: publicKey);
304: this .setDirty();
305: this .doInformationChanged();
306:
307: }
308:
309: public final void setName(String name) {
310:
311: information.put(VirtualElement.STRING_NAME, name);
312: this .setDirty();
313: this .doInformationChanged();
314:
315: }
316:
317: public final void setVersion(String version) {
318:
319: information.put(VirtualElement.STRING_VERSION, version);
320: this .setDirty();
321: this .doInformationChanged();
322:
323: }
324:
325: //obliterates every previously stored information except reserved fields
326: public void setInformation(Hashtable information) {
327:
328: this .information = information;
329: this .setDirty();
330: this .doInformationChanged();
331:
332: }
333:
334: //use the corresponding method to set the individual default fields
335: public void addInformation(String key, String keyValue) {
336:
337: //check if it is a reserved field or not
338: if ((key != VirtualElement.STRING_DATE)
339: && (key != VirtualElement.STRING_AUTHOR_NAME)
340: && (key != VirtualElement.STRING_AUTHOR_E_MAIL)
341: && (key != VirtualElement.STRING_AUTHOR_PUBLIC_KEY)
342: && (key != VirtualElement.STRING_NAME)
343: && (key != VirtualElement.STRING_VERSION)) {
344: this .information.put(key, keyValue);
345: this .setDirty();
346: this .doInformationChanged();
347: } else {
348: throw new IllegalArgumentException(
349: "You can't add directely Information on the restricted fields.");
350: }
351:
352: }
353:
354: public void removeInformation(String key) {
355:
356: //check if it is a reserved field or not
357: if ((key != VirtualElement.STRING_DATE)
358: && (key != VirtualElement.STRING_AUTHOR_NAME)
359: && (key != VirtualElement.STRING_AUTHOR_E_MAIL)
360: && (key != VirtualElement.STRING_AUTHOR_PUBLIC_KEY)
361: && (key != VirtualElement.STRING_NAME)
362: && (key != VirtualElement.STRING_VERSION)) {
363: this .information.remove(key);
364: this .setDirty();
365: this .doInformationChanged();
366: } else {
367: throw new IllegalArgumentException(
368: "You can't remove directely Information on the restricted fields.");
369: }
370:
371: }
372:
373: //must be >= 0
374: public void setPrice(double price) {
375:
376: if (price >= 0) {
377: this .price = price;
378: this .setDirty();
379: this .doPriceChanged();
380: }
381:
382: }
383:
384: //any valid string will fit
385: public void setCurrency(String currency) {
386:
387: if ((currency != null) && currency.length() > 0) {
388: this .currency = currency;
389: this .setDirty();
390: this .doCurrencyChanged();
391: }
392:
393: }
394:
395: public final int[] getOthersAccessRights() {
396:
397: return this .othersAccessRights;
398:
399: }
400:
401: public final int getOthersAccessRights(int userKind) {
402:
403: switch (userKind) {
404: case Avatar.PEERSLORD:
405: return this .othersAccessRights[0];
406: case Avatar.PEER:
407: return this .othersAccessRights[1];
408: case Avatar.PEERSVASSAL:
409: return this .othersAccessRights[2];
410: case Avatar.VASSAL:
411: return this .othersAccessRights[3];
412: default:
413: return 0;
414: }
415:
416: }
417:
418: //capability works as a mask
419: public final boolean getOthersAccessRight(int userKind,
420: int capability) {
421:
422: return (this .getOthersAccessRights(userKind) & capability) != 0;
423:
424: }
425:
426: //this is not a mask, all capabilities are set at once
427: //setting an access right for a capability doesn't ensure that the designer has designed a valid action for that capability
428: public final void setOthersAccessRights(int userKind, int capability) {
429:
430: if ((capability >= VirtualElement.HIDDEN)
431: && (capability <= VirtualElement.READ_WRITE)) {
432: switch (userKind) {
433: case Avatar.PEERSLORD:
434: othersAccessRights[0] = capability;
435: case Avatar.PEER:
436: othersAccessRights[1] = capability;
437: case Avatar.PEERSVASSAL:
438: othersAccessRights[2] = capability;
439: case Avatar.VASSAL:
440: othersAccessRights[3] = capability;
441: this .setDirty();
442: this .doOthersAccessRightsChanged();
443: }
444: }
445:
446: }
447:
448: //will set for all users kinds
449: //this is not a mask, all capabilities are set at once
450: //setting an access right for a capability doesn't ensure that the designer has designed a valid action for that capability
451: public final void setOthersAccessRights(int capability) {
452:
453: if ((capability >= VirtualElement.HIDDEN)
454: && (capability <= VirtualElement.READ_WRITE)) {
455: othersAccessRights[0] = capability;
456: othersAccessRights[1] = capability;
457: othersAccessRights[2] = capability;
458: othersAccessRights[3] = capability;
459: this .setDirty();
460: this .doOthersAccessRightsChanged();
461: }
462: }
463:
464: public final boolean getDesignerCapability(int capability) {
465:
466: return (this .getDesignerCapabilities() & capability) != 0;
467:
468: }
469:
470: public int getDesignerCapabilities() {
471:
472: //The designer of the object has to encode the desired feature mask of its object
473: //by setting objectCapabilities
474: //just to ensure no one will subclass his object to do undesired behaviors
475: //Designers should use the modifier "final" to ensure there is no one counterfeiting their identity
476:
477: return this .virtualElementCapabilities;
478:
479: }
480:
481: public final WorldSpot getWorldSpot(Avatar caller) {
482:
483: Transform3D transform3D;
484: Point3d point3d;
485: Transaction transaction;
486: Extent extent;
487: Query query;
488: String filter;
489: Collection collection;
490:
491: if ((caller != null) && (caller.getSkin() != null)) {
492: transform3D = caller.getSkin().getTransform3D();
493: point3d = new Point3d();
494: transform3D.transform(point3d);
495:
496: try {
497: transaction = this .getPersistenceManager()
498: .currentTransaction();
499: transaction.begin();
500:
501: extent = this .getPersistenceManager().getExtent(
502: WorldSpot.class, true);
503: filter = new String(
504: "SELECT WorldSpot FROM WorldSpot w WHERE w.getBounds().intersect(point3d)");
505: query = this .getPersistenceManager().newQuery(
506: WorldSpot.class, extent, filter);
507: collection = (Collection) query.execute();
508:
509: transaction.commit();
510:
511: //each object should be in exactly one worldSpot at a time
512: return (WorldSpot) (collection.iterator().next());
513:
514: } catch (Exception exception) {
515:
516: return null;
517:
518: }
519:
520: } else {
521: return null;
522: }
523:
524: }
525:
526: //delete VirtualElement: ObjectWorld (ObjectWorld, Skin, ToolWorld and GuideWorld), Land, BackgroundWorld
527: //does not send any notification to the server
528: protected final void deleteVirtualElement(
529: VirtualElement virtualElement) {
530:
531: Transaction transaction;
532: Extent extent;
533: Query query;
534: String filter;
535: Collection collection;
536: Collection collection1;
537: Collection collection2;
538: Collection collection3;
539: Collection collection4;
540:
541: if (virtualElement != null) {
542:
543: collection = new HashSet();
544:
545: try {
546: transaction = this .getPersistenceManager()
547: .currentTransaction();
548: transaction.begin();
549:
550: extent = this .getPersistenceManager().getExtent(
551: Ticket.class, true);
552: filter = new String(
553: "SELECT Ticket FROM Ticket t WHERE t.getVirtualElement()==virtualElement");
554: query = this .getPersistenceManager().newQuery(
555: Ticket.class, extent, filter);
556: collection1 = (Collection) query.execute();
557:
558: transaction.commit();
559:
560: collection.addAll(collection1);
561:
562: } catch (Exception exception) {
563: }
564:
565: try {
566: transaction = this .getPersistenceManager()
567: .currentTransaction();
568: transaction.begin();
569:
570: extent = this .getPersistenceManager().getExtent(
571: Pass.class, true);
572: filter = new String(
573: "SELECT Pass FROM Pass p WHERE p.getObject()==virtualElement");
574: query = this .getPersistenceManager().newQuery(
575: Pass.class, extent, filter);
576: collection2 = (Collection) query.execute();
577:
578: transaction.commit();
579:
580: collection.addAll(collection2);
581:
582: } catch (Exception exception) {
583: }
584:
585: try {
586: transaction = this .getPersistenceManager()
587: .currentTransaction();
588: transaction.begin();
589:
590: extent = this .getPersistenceManager().getExtent(
591: Filter.class, true);
592: filter = new String(
593: "SELECT Filter FROM Filter f WHERE f.getObject()==virtualElement");
594: query = this .getPersistenceManager().newQuery(
595: Filter.class, extent, filter);
596: collection3 = (Collection) query.execute();
597:
598: transaction.commit();
599:
600: collection.addAll(collection3);
601:
602: } catch (Exception exception) {
603: }
604:
605: try {
606: transaction = this .getPersistenceManager()
607: .currentTransaction();
608: transaction.begin();
609:
610: extent = this .getPersistenceManager().getExtent(
611: Blocker.class, true);
612: filter = new String(
613: "SELECT Blocker FROM Blocker b WHERE b.getObject()==virtualElement");
614: query = this .getPersistenceManager().newQuery(
615: Blocker.class, extent, filter);
616: collection4 = (Collection) query.execute();
617:
618: transaction.commit();
619:
620: collection.addAll(collection4);
621:
622: } catch (Exception exception) {
623: }
624:
625: //update database
626: try {
627: transaction = this .getPersistenceManager()
628: .currentTransaction();
629: transaction.begin();
630:
631: this .getPersistenceManager().deletePersistentAll(
632: collection);
633: this .getPersistenceManager().deletePersistent(
634: virtualElement);
635:
636: transaction.commit();
637: } catch (Exception exception) {
638: }
639:
640: this .notifyFilterers(Filter.DELETION, virtualElement);
641: virtualElement = null;
642:
643: }
644:
645: }
646:
647: //owner can also be a Lord of virtualElement owner
648: public final void deleteVirtualElement(Avatar caller,
649: VirtualElement virtualElement) {
650:
651: int relation;
652:
653: if ((caller != null) && (virtualElement != null)) {
654: relation = Avatar.getFeudalRelation(caller, virtualElement
655: .getUserOwner());
656: if ((relation == Avatar.LORD) || (relation == Avatar.SELF)) {
657: this .deleteVirtualElement(virtualElement);
658: }
659: }
660:
661: }
662:
663: //used for addidtion and deletion but NOT for read or write access
664: protected final void notifyFilterers(int accessKind,
665: Object virtualElement) {
666:
667: Transaction transaction;
668: Extent extent;
669: Query query;
670: Collection collection;
671: Iterator iterator;
672: Filter aFilter;
673: String filter;
674:
675: try {
676: transaction = this .getPersistenceManager()
677: .currentTransaction();
678: transaction.begin();
679:
680: extent = this .getPersistenceManager().getExtent(
681: Filter.class, true);
682: filter = new String(
683: "SELECT Filter FROM Filter f WHERE f.getObject()==virtualElement");
684: query = this .getPersistenceManager().newQuery(Filter.class,
685: extent, filter);
686: collection = (Collection) query.execute();
687:
688: transaction.commit();
689:
690: iterator = collection.iterator();
691: while (iterator.hasNext()) {
692: aFilter = (Filter) iterator.next();
693: if (aFilter.getAccessKind() == accessKind) {
694: if (accessKind == Filter.ADDITION) {
695: this .getUniverseServer()
696: .sendAdditionNotification(
697: aFilter.getRequester(),
698: virtualElement);
699: } else {
700: //Filter.DELETION
701: this .getUniverseServer()
702: .sendDeletionNotification(
703: aFilter.getRequester(),
704: virtualElement.hashCode());
705: }
706: }
707: }
708:
709: } catch (Exception exception) {
710: }
711:
712: }
713:
714: //used for client to server communication
715: //should be unique for each virtualElement
716: public final int hashCode() {
717:
718: return super .hashCode();
719:
720: }
721:
722: //time sliced actions
723:
724: //see buying and selling system for Object sales
725:
726: //when the object is proposed on a sale in a pool
727: public void doSale(Pool pool) {
728:
729: }
730:
731: //when an offer is made for this virtualElement
732: public void doOffer(TaggedVirtualElement taggedVirtualElement) {
733:
734: }
735:
736: //when an offer is removed for this virtualElement
737: public void doCancelOffer(TaggedVirtualElement taggedVirtualElement) {
738:
739: }
740:
741: //when the owner cancels the sale
742: public void doCancelSale() {
743:
744: }
745:
746: //when the object is removed from a sale by an avatar who buys it
747: //(avatar is the new owner if any, null if object hasn't been sold)
748: public void doBuy(Avatar newOwner) {
749:
750: }
751:
752: public void doUserOwnerChanged() {
753:
754: }
755:
756: public void doInformationChanged() {
757:
758: }
759:
760: public void doPriceChanged() {
761:
762: }
763:
764: public void doCurrencyChanged() {
765:
766: }
767:
768: public void doOthersAccessRightsChanged() {
769:
770: }
771:
772: //SceneGraph serialization for Geometry and Sound
773: public void createSceneGraphObjectReferences(
774: SceneGraphObjectReferenceControl ref) {
775:
776: }
777:
778: public void restoreSceneGraphObjectReferences(
779: SceneGraphObjectReferenceControl ref) {
780:
781: }
782:
783: public void writeSceneGraphObject(java.io.DataOutput out)
784: throws IOException {
785:
786: }
787:
788: public void readSceneGraphObject(java.io.DataInput in)
789: throws IOException {
790:
791: }
792:
793: public boolean saveChildren() {
794:
795: return true;
796:
797: }
798:
799: }
|