/** * Copyright (c) 2006-2011 Floggy Open Source Group. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.sourceforge.floggy.persistence.impl; import java.io.ByteArrayInputStream; import java.io.DataInputStream; import java.io.IOException; import java.util.Enumeration; import java.util.Hashtable; import java.util.Vector; import javax.microedition.rms.RecordEnumeration; import javax.microedition.rms.RecordStore; import javax.microedition.rms.RecordStoreException; /** * DOCUMENT ME! * * @author <a href="mailto:thiago.moreira@floggy.org">Thiago Moreira</a> * @version $Revision$ */ public class PersistableMetadataManager { public static final String VERSION_1_0_1 = "1.0.1"; public static final String VERSION_1_1_0 = "1.1.0"; public static final String VERSION_1_1_1 = "1.1.1"; public static final String VERSION_1_2_0 = "1.2.0"; public static final String VERSION_1_3_0 = "1.3.0"; public static final String VERSION_1_4_0 = "1.4.0"; public static final String CURRENT_VERSION = VERSION_1_4_0; private static String rmsVersion; private static Hashtable classBasedMetadatas; private static Hashtable rmsBasedMetadatas; private static Vector notMigratedClassNames; /** * Creates a new PersistableMetadataManager object. */ protected PersistableMetadataManager() { } /** * DOCUMENT ME! * * @param metadata DOCUMENT ME! */ public static void addRMSMetadata(PersistableMetadata metadata) { rmsBasedMetadatas.put(metadata.getClassName(), metadata); notMigratedClassNames.removeElement(metadata.getClassName()); } /** * DOCUMENT ME! * * @param metadata DOCUMENT ME! * * @return DOCUMENT ME! */ public static boolean containsRMSMetadata(PersistableMetadata metadata) { return rmsBasedMetadatas.containsKey(metadata.getClassName()); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static String getBytecodeVersion() { return CURRENT_VERSION; } /** * DOCUMENT ME! * * @param className DOCUMENT ME! * * @return DOCUMENT ME! */ public static PersistableMetadata getClassBasedMetadata(String className) { return (PersistableMetadata) classBasedMetadatas.get(className); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static Enumeration getClassBasedMetadatas() { return classBasedMetadatas.elements(); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static Vector getNotMigratedClasses() { return notMigratedClassNames; } /** * DOCUMENT ME! * * @param className DOCUMENT ME! * * @return DOCUMENT ME! */ public static PersistableMetadata getRMSBasedMetadata(String className) { return (PersistableMetadata) rmsBasedMetadatas.get(className); } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public static String getRMSVersion() { return rmsVersion; } /** * DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public static void init() throws Exception { } /** * DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public static void load() throws Exception { notMigratedClassNames = new Vector(); RecordStore rs = RecordStore.openRecordStore("FloggyProperties", true); if (rs.getNumRecords() != 0) { deserialize(rs.getRecord(1)); loadRMSStructure(); } else { rmsVersion = CURRENT_VERSION; save(rs); } if (classBasedMetadatas != null) { Enumeration classNames = classBasedMetadatas.keys(); while (classNames.hasMoreElements()) { String className = (String) classNames.nextElement(); PersistableMetadata classBasedMetadata = (PersistableMetadata) classBasedMetadatas.get(className); PersistableMetadata rmsBasedMetadata = (PersistableMetadata) rmsBasedMetadatas.get(className); if (!classBasedMetadata.equals(rmsBasedMetadata)) { notMigratedClassNames.addElement(className); } } } } /** * DOCUMENT ME! */ public static void reset() { classBasedMetadatas.clear(); rmsBasedMetadatas.clear(); notMigratedClassNames.removeAllElements(); } /** * DOCUMENT ME! * * @param metadata DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public static void saveRMSStructure(PersistableMetadata metadata) throws Exception { String[] fieldNames = metadata.getFieldNames(); int[] fieldTypes = metadata.getFieldTypes(); String recordStoreVersion = metadata.getRecordStoreVersion(); recordStoreVersion = (recordStoreVersion == null) ? getRMSVersion() : recordStoreVersion; FloggyOutputStream out = new FloggyOutputStream(); out.writeUTF(metadata.getClassName()); out.writeBoolean(metadata.isAbstract()); SerializationManager.writeString(out, metadata.getSuperClassName()); out.writeInt(fieldTypes.length); for (int i = 0; i < fieldTypes.length; i++) { out.writeUTF(fieldNames[i]); out.writeInt(fieldTypes[i]); } SerializationManager.writeHashtable(out, metadata.getPersistableImplementations()); out.writeUTF(metadata.getRecordStoreName()); out.writeInt(metadata.getPersistableStrategy()); SerializationManager.writeIndexMetadata(out, metadata.getIndexMetadatas()); out.writeUTF(recordStoreVersion); byte[] data = out.toByteArray(); RecordStore rs = RecordStore.openRecordStore("FloggyProperties", true); int recordId = metadata.getRecordId(); if (recordId != -1) { rs.setRecord(recordId, data, 0, data.length); } else { metadata.setRecordId(rs.addRecord(data, 0, data.length)); } addRMSMetadata(metadata); } private static void deserialize(byte[] data) throws IOException { DataInputStream dis = new DataInputStream(new ByteArrayInputStream(data)); while (dis.available() != 0) { String field = dis.readUTF(); if ("version".equals(field)) { rmsVersion = dis.readUTF(); } } } private static void loadRMSStructure() throws Exception { RecordStore rs = RecordStore.openRecordStore("FloggyProperties", true); RecordEnumeration enumeration = rs.enumerateRecords(null, null, false); while (enumeration.hasNextElement()) { int recordId = enumeration.nextRecordId(); DataInputStream dis = new DataInputStream(new ByteArrayInputStream(rs.getRecord(recordId))); String className = dis.readUTF(); if (!"version".equals(className)) { boolean isAbstract = dis.readBoolean(); String superClassName = SerializationManager.readString(dis); String[] fieldNames = new String[dis.readInt()]; int[] fieldTypes = new int[fieldNames.length]; for (int i = 0; i < fieldNames.length; i++) { fieldNames[i] = dis.readUTF(); fieldTypes[i] = dis.readInt(); } Hashtable persistableImplementations = SerializationManager.readHashtable(dis); String recordStoreName = dis.readUTF(); int persistableStrategy = PersistableMetadata.JOINED_STRATEGY; if (dis.available() != 0) { persistableStrategy = dis.readInt(); } Vector indexMetadatas = null; if (dis.available() != 0) { indexMetadatas = SerializationManager.readIndexMetadata(dis); } String recordStoreVersion = getRMSVersion(); if (dis.available() != 0) { recordStoreVersion = dis.readUTF(); } addRMSMetadata(new PersistableMetadata(isAbstract, className, superClassName, fieldNames, fieldTypes, persistableImplementations, indexMetadatas, recordStoreName, recordStoreVersion, persistableStrategy, recordId)); } } } private static void save(RecordStore rs) throws IOException, RecordStoreException { byte[] data = serialize(); if (rs.getNumRecords() == 1) { rs.setRecord(1, data, 0, data.length); } else { rs.addRecord(data, 0, data.length); } } private static byte[] serialize() throws IOException { FloggyOutputStream fos = new FloggyOutputStream(); fos.writeUTF("version"); fos.writeUTF(rmsVersion); return fos.toByteArray(); } }