001 /*
002 * Cumulus4j - Securing your data in the cloud - http://cumulus4j.org
003 * Copyright (C) 2011 NightLabs Consulting GmbH
004 *
005 * This program is free software: you can redistribute it and/or modify
006 * it under the terms of the GNU Affero General Public License as
007 * published by the Free Software Foundation, either version 3 of the
008 * License, or (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful,
011 * but WITHOUT ANY WARRANTY; without even the implied warranty of
012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
013 * GNU Affero General Public License for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License
016 * along with this program. If not, see <http://www.gnu.org/licenses/>.
017 */
018 package org.cumulus4j.store.model;
019
020 import java.io.Serializable;
021 import java.util.Collections;
022 import java.util.Date;
023 import java.util.HashMap;
024 import java.util.Map;
025
026 /**
027 * <p>
028 * Container holding the values of a persistent object.
029 * </p>
030 * <p>
031 * Objects to be stored in the database, are first represented by an instance of {@link ObjectContainer} and
032 * then serialised into a byte-array, which is finally encrypted and put into a {@link DataEntry}'s {@link DataEntry#getValue() value}.
033 * </p>
034 * <p>
035 * Note, that references to other objects
036 * are either not stored at all (in a "mapped-by"-relationship) or stored via the other object's
037 * {@link DataEntry#getDataEntryID() dataEntryID}; a persistent object is never stored as-is.
038 * </p>
039 *
040 * @author Marco หงุ่ยตระกูล-Schulze - marco at nightlabs dot de
041 */
042 public class ObjectContainer
043 implements Serializable, Cloneable
044 {
045 private static final long serialVersionUID = 4L;
046
047 /**
048 * Stores the concrete value of a field mapped by the persistent {@link FieldMeta#getFieldID() fieldID}.
049 * If the value originally was a persistable object, it is replaced by its object-ID.
050 */
051 private Map<Long, Object> fieldID2value = new HashMap<Long, Object>();
052
053 private Object version;
054
055 public ObjectContainer() { }
056
057 // TODO maybe do custom serialisation/deserialisation in order to better keep compatibility? Or should we maybe instead use
058 // ObjectContainer2, ObjectContainer3 etc. (i.e. other classes)?
059 // private void writeObject(java.io.ObjectOutputStream out)
060 // throws IOException
061 // {
062 // out.defaultWriteObject();
063 // }
064 //
065 // private void readObject(java.io.ObjectInputStream in)
066 // throws IOException, ClassNotFoundException
067 // {
068 // in.defaultReadObject();
069 // }
070 //
071 // @SuppressWarnings("unused") // this method seems to be so new to Java that the Eclipse compiler doesn't know it yet and shows a warning.
072 // private void readObjectNoData()
073 // throws ObjectStreamException
074 // {
075 // // no special handling necessary
076 // }
077
078 /**
079 * Get a value.
080 * @param fieldID the field's persistent ID, i.e. a reference to {@link FieldMeta#getFieldID() FieldMeta.fieldID}.
081 * @return the value or <code>null</code>.
082 */
083 public Object getValue(long fieldID)
084 {
085 return fieldID2value.get(fieldID);
086 }
087
088 /**
089 * Set a value.
090 * @param fieldID the field's persistent ID, i.e. a reference to {@link FieldMeta#getFieldID() FieldMeta.fieldID}.
091 * @param value either the raw value or the object-ID of a persistable object. Persistable objects are never stored
092 * directly in an <code>ObjectContainer</code>.
093 */
094 public void setValue(long fieldID, Object value)
095 {
096 if (value == null)
097 fieldID2value.remove(fieldID);
098 else
099 fieldID2value.put(fieldID, value);
100 }
101
102 public Map<Long, Object> getFieldID2value() {
103 return Collections.unmodifiableMap(fieldID2value);
104 }
105
106 /**
107 * Get the object's version or <code>null</code>, if the persistence-capable class has no versioning enabled.
108 * The version can be a {@link Long}, a {@link Date} or anything else supported by DataNucleus/JDO.
109 * @return the object's version or <code>null</code>.
110 */
111 public Object getVersion() {
112 return version;
113 }
114 public void setVersion(Object version) {
115 this.version = version;
116 }
117
118 @Override
119 public ObjectContainer clone()
120 {
121 ObjectContainer clone;
122 try {
123 clone = (ObjectContainer) super.clone();
124 } catch (CloneNotSupportedException e) {
125 throw new RuntimeException(e); // should never happen => wrap as RuntimeException!
126 }
127 clone.fieldID2value = new HashMap<Long, Object>(this.fieldID2value);
128 return clone;
129 }
130 }