View Javadoc

1   /**
2    * Copyright (c) 2011, University of Konstanz, Distributed Systems Group
3    * All rights reserved.
4    * 
5    * Redistribution and use in source and binary forms, with or without
6    * modification, are permitted provided that the following conditions are met:
7    * * Redistributions of source code must retain the above copyright
8    * notice, this list of conditions and the following disclaimer.
9    * * Redistributions in binary form must reproduce the above copyright
10   * notice, this list of conditions and the following disclaimer in the
11   * documentation and/or other materials provided with the distribution.
12   * * Neither the name of the University of Konstanz nor the
13   * names of its contributors may be used to endorse or promote products
14   * derived from this software without specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17   * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18   * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19   * DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
20   * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21   * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23   * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25   * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26   */
27  package org.treetank.access.conf;
28  
29  import static com.google.common.base.Objects.toStringHelper;
30  
31  import java.io.File;
32  import java.io.FileReader;
33  import java.io.FileWriter;
34  import java.io.IOException;
35  import java.lang.reflect.Constructor;
36  import java.lang.reflect.InvocationTargetException;
37  import java.util.ArrayList;
38  import java.util.List;
39  import java.util.Objects;
40  import java.util.Properties;
41  
42  import org.treetank.access.Session;
43  import org.treetank.api.IMetaEntryFactory;
44  import org.treetank.api.IDataFactory;
45  import org.treetank.exception.TTIOException;
46  import org.treetank.io.IBackend;
47  import org.treetank.io.IBackend.IBackendFactory;
48  import org.treetank.io.bytepipe.ByteHandlerPipeline;
49  import org.treetank.io.bytepipe.Encryptor;
50  import org.treetank.io.bytepipe.IByteHandler;
51  import org.treetank.io.bytepipe.IByteHandler.IByteHandlerPipeline;
52  import org.treetank.revisioning.IRevisioning;
53  
54  import com.google.gson.stream.JsonReader;
55  import com.google.gson.stream.JsonWriter;
56  import com.google.inject.Inject;
57  import com.google.inject.assistedinject.Assisted;
58  
59  /**
60   * <h1>ResourceConfiguration</h1>
61   * 
62   * <p>
63   * Holds the settings for a resource which acts as a base for session that can not change. This includes all
64   * settings which are persistent. Each {@link ResourceConfiguration} is furthermore bound to one fixed
65   * database denoted by a related {@link StorageConfiguration}.
66   * </p>
67   * 
68   * @author Sebastian Graf, University of Konstanz
69   */
70  public final class ResourceConfiguration {
71  
72      /**
73       * Paths for a {@link Session}. Each resource has the same folder.layout.
74       */
75      public enum Paths implements IConfigurationPath {
76  
77          /** Folder for storage of data. */
78          Data(new File("data"), true),
79          /** Folder for transaction log. */
80          TransactionLog(new File("log"), true),
81          /** File to store the resource settings. */
82          ConfigBinary(new File("ressetting.obj"), false);
83  
84          /** Location of the file. */
85          private final File mFile;
86  
87          /** Is the location a folder or no? */
88          private final boolean mIsFolder;
89  
90          /**
91           * Constructor.
92           * 
93           * @param pFile
94           *            to be set
95           * @param pIsFolder
96           *            to be set.
97           */
98          private Paths(final File pFile, final boolean pIsFolder) {
99              this.mFile = pFile;
100             this.mIsFolder = pIsFolder;
101         }
102 
103         /**
104          * Getting the file for the kind.
105          * 
106          * @return the file to the kind
107          */
108         public File getFile() {
109             return mFile;
110         }
111 
112         /**
113          * Check if file is denoted as folder or not.
114          * 
115          * @return boolean if file is folder
116          */
117         public boolean isFolder() {
118             return mIsFolder;
119         }
120 
121     }
122 
123     // MEMBERS FOR FIXED FIELDS
124     /** Type of Storage (File, Berkeley). */
125     public final IBackend mBackend;
126 
127     /** Kind of revisioning (Incremental, Differential). */
128     public final IRevisioning mRevision;
129 
130     /** Path for the resource to be associated. */
131     public final Properties mProperties;
132 
133     /** Data Factory for deserializing data. */
134     public final IDataFactory mDataFac;
135 
136     /** MetaEntry Factory for deserializing meta-entries. */
137     public final IMetaEntryFactory mMetaFac;
138 
139     // END MEMBERS FOR FIXED FIELDS
140 
141     /**
142      * Convenience constructor using the standard settings.
143      * 
144      * @param pProperties
145      * @param pBackend
146      * @param pRevision
147      * @param pDataFac
148      */
149     @Inject
150     public ResourceConfiguration(@Assisted Properties pProperties, IBackendFactory pBackend,
151         IRevisioning pRevision, IDataFactory pDataFac, IMetaEntryFactory pMetaFac) {
152 
153         this(pProperties, pBackend.create(pProperties), pRevision, pDataFac, pMetaFac);
154     }
155 
156     /**
157      * Constructor.
158      * 
159      * @param pProperties
160      * @param pStorage
161      * @param pRevisioning
162      * @param pDataFac
163      * @param pMetaFac
164      */
165     public ResourceConfiguration(Properties pProperties, IBackend pStorage, IRevisioning pRevisioning,
166         IDataFactory pDataFac, IMetaEntryFactory pMetaFac) {
167         mProperties = pProperties;
168         mBackend = pStorage;
169         mRevision = pRevisioning;
170         mDataFac = pDataFac;
171         mMetaFac = pMetaFac;
172     }
173 
174     /**
175      * 
176      * Factory for generating an {@link ResourceConfiguration}-instance. Needed mainly
177      * because of Guice-Assisted utilization.
178      * 
179      * @author Sebastian Graf, University of Konstanz
180      * 
181      */
182     public static interface IResourceConfigurationFactory {
183 
184         /**
185          * Generating a storage for a fixed file.
186          * 
187          * 
188          * @param pProperties
189          *            Properties of resource to be set.
190          * @return an {@link ResourceConfiguration}-instance
191          */
192         ResourceConfiguration create(Properties pProperties);
193     }
194 
195     private static final String[] JSONNAMES = {
196         "metaentryClass", "revisioningClass", "DataFactoryClass", "byteHandlerClasses", "storageClass",
197         "properties"
198     };
199 
200     public static void serialize(final ResourceConfiguration pConfig) throws TTIOException {
201         try {
202 
203             final File file =
204                 new File(new File(new File(pConfig.mProperties.getProperty(ConstructorProps.STORAGEPATH),
205                     StorageConfiguration.Paths.Data.getFile().getName()), pConfig.mProperties
206                     .getProperty(ConstructorProps.RESOURCE)), Paths.ConfigBinary.getFile().getName());
207 
208             FileWriter fileWriter = new FileWriter(file);
209             JsonWriter jsonWriter = new JsonWriter(fileWriter);
210             jsonWriter.beginObject();
211             // caring about the meta-entries
212             jsonWriter.name(JSONNAMES[0]).value(pConfig.mMetaFac.getClass().getName());
213             // caring about the versioning
214             jsonWriter.name(JSONNAMES[1]).value(pConfig.mRevision.getClass().getName());
215             // caring about the DataFactory
216             jsonWriter.name(JSONNAMES[2]).value(pConfig.mDataFac.getClass().getName());
217             // caring about the ByteHandlers
218             IByteHandlerPipeline byteHandler = pConfig.mBackend.getByteHandler();
219             jsonWriter.name(JSONNAMES[3]);
220             jsonWriter.beginArray();
221             for (IByteHandler handler : byteHandler) {
222                 jsonWriter.value(handler.getClass().getName());
223             }
224             jsonWriter.endArray();
225             // caring about the storage
226             jsonWriter.name(JSONNAMES[4]).value(pConfig.mBackend.getClass().getName());
227             jsonWriter.name(JSONNAMES[5]);
228             jsonWriter.beginObject();
229             for (String key : pConfig.mProperties.stringPropertyNames()) {
230                 jsonWriter.name(key).value(pConfig.mProperties.getProperty(key));
231             }
232             jsonWriter.endObject();
233             jsonWriter.endObject();
234             jsonWriter.close();
235             fileWriter.close();
236         } catch (final IOException exc) {
237             throw new TTIOException(exc);
238         }
239     }
240 
241     /**
242      * Deserializing a Resourceconfiguration out of a JSON-file from the persistent storage.
243      * The order is important and the reader is passed through the objects as visitor.
244      * 
245      * @param pFile
246      *            where the resource lies in.
247      * @return a complete {@link ResourceConfiguration} instance.
248      * @throws TTIOException
249      */
250     public static ResourceConfiguration deserialize(final File pFile, final String pResource)
251         throws TTIOException {
252         try {
253 
254             final File file =
255                 new File(new File(new File(pFile, StorageConfiguration.Paths.Data.getFile().getName()),
256                     pResource), Paths.ConfigBinary.getFile().getName());
257 
258             FileReader fileReader = new FileReader(file);
259             JsonReader jsonReader = new JsonReader(fileReader);
260             jsonReader.beginObject();
261             // caring about the kind of the metabucket
262             jsonReader.nextName().equals(JSONNAMES[0]);
263             Class<?> metaBucketClazz = Class.forName(jsonReader.nextString());
264             // caring about the versioning
265             jsonReader.nextName().equals(JSONNAMES[1]);
266             Class<?> revClazz = Class.forName(jsonReader.nextString());
267             // caring about the DataFactory
268             jsonReader.nextName().equals(JSONNAMES[2]);
269             Class<?> dataFacClazz = Class.forName(jsonReader.nextString());
270 
271             // caring about the ByteHandlers
272             List<IByteHandler> handlerList = new ArrayList<IByteHandler>();
273             if (jsonReader.nextName().equals(JSONNAMES[3])) {
274                 jsonReader.beginArray();
275                 while (jsonReader.hasNext()) {
276                     Class<?> handlerClazz = Class.forName(jsonReader.nextString());
277                     Constructor<?> handlerCons = handlerClazz.getConstructors()[0];
278                     if (handlerClazz.getName().equals(Encryptor.class.getName())) {
279                         handlerList.add((IByteHandler)handlerCons.newInstance(StandardSettings.KEY));
280                     } else {
281                         handlerList.add((IByteHandler)handlerCons.newInstance());
282                     }
283 
284                 }
285                 jsonReader.endArray();
286             }
287             ByteHandlerPipeline pipeline =
288                 new ByteHandlerPipeline(handlerList.toArray(new IByteHandler[handlerList.size()]));
289             // caring about the storage
290             jsonReader.nextName().equals(JSONNAMES[4]);
291             Class<?> storageClazz = Class.forName(jsonReader.nextString());
292             jsonReader.nextName().equals(JSONNAMES[5]);
293             Properties props = new Properties();
294             jsonReader.beginObject();
295             while (jsonReader.hasNext()) {
296                 props.setProperty(jsonReader.nextName(), jsonReader.nextString());
297             }
298             jsonReader.endObject();
299             jsonReader.endObject();
300             jsonReader.close();
301             fileReader.close();
302 
303             Constructor<?> metaBucketCons = metaBucketClazz.getConstructors()[0];
304             IMetaEntryFactory metaFac = (IMetaEntryFactory)metaBucketCons.newInstance();
305 
306             Constructor<?> dataFacCons = dataFacClazz.getConstructors()[0];
307             IDataFactory dataFactory = (IDataFactory)dataFacCons.newInstance();
308 
309             Constructor<?> revCons = revClazz.getConstructors()[0];
310             IRevisioning revObject = (IRevisioning)revCons.newInstance();
311 
312             Constructor<?> storageCons = storageClazz.getConstructors()[0];
313             IBackend backend = (IBackend)storageCons.newInstance(props, dataFactory, metaFac, pipeline);
314 
315             return new ResourceConfiguration(props, backend, revObject, dataFactory, metaFac);
316 
317         } catch (IOException | ClassNotFoundException | InstantiationException | IllegalAccessException
318         | InvocationTargetException exc) {
319             throw new TTIOException(exc);
320         }
321     }
322 
323     /**
324      * {@inheritDoc}
325      */
326     @Override
327     public int hashCode() {
328         return Objects.hash(mBackend, mRevision, mProperties, mDataFac);
329     }
330 
331     /**
332      * {@inheritDoc}
333      */
334     @Override
335     public final boolean equals(final Object pObj) {
336         return this.hashCode() == pObj.hashCode();
337     }
338 
339     /**
340      * {@inheritDoc}
341      */
342     @Override
343     public String toString() {
344         return toStringHelper(this).add("mBackend", mBackend.getClass()).add("mRevision", mRevision).add(
345             "mProperties", mProperties).add("mDataFac", mDataFac.getClass().getName()).toString();
346     }
347 }