Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DBInfo.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DBInfo.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DBInfo.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DBInfo.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,430 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.InputStream; +import java.io.IOException; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.util.I18NHelper; +import org.netbeans.mdr.persistence.Streamable; +import org.netbeans.mdr.persistence.StorageException; +import org.netbeans.mdr.persistence.StorageIOException; + +/** +* This class represents the information about the contents of the store +* itself which must be durable across JVMs. +* <p> +* This class is <code>public</code> so that it can be used as a +* <code>Streamable</code> and stored in the database. +* +* @author Dave Bristor +*/ +// Streamable requires that the class be public. I think!. +// This class is server-side only, not needed in client. +public class DBInfo implements Streamable { + // There is only ever one instance of DBInfo in a store. + // + // When a database is first created, we use the initial values here + // specified. If the database is being brought up from an existing + // backing store, then the read method below will provide the correct + // values from the store. + // + private FOStoreDatabase fodb = null; + + /** + * This is the OID of the DBInfo. + */ + // See CLID.java: This relies on the facts that (a) CLID's less than 100 + // are reserved, and (b) the primitive types are final and cannot be + // subclassed. + private static final OID dbInfoOID = new OID(0); + + // Next available CLID. + private CLID nextCLID = CLID.firstCLID; + + // For the OID of the DBClass corresponding to a given CLID. + private static final int DBCLASS_UID = 0; + + // For the OID of the OID's which are of DBClass instances that are + // subclasses of an OID's CLID's class. Got that? No? Then see + // GetExtentHandler.java. + private static final int SUBCLASS_UID = 1; + + // For the OID of the extent of instances of the class indicated by a + // CLID. + private static final int EXTENT_UID = 2; + + // Reserve the first N UID's in each OID for future use. + // + // Note to maintainers: Make sure that this is greater than + // LAST_RESERVED_UID. + private static final int FIRST_CLASS_UID = 10; + + // Indexed by CLID: the value in a given position is the value of the + // next available UID for that CLID. That is, when we need a new + // datastore OID for a particular CLID, we use that CLID's id value as an + // index into this list, and extract the value there. We use that value + // as the UID part of the OID being created. And we update the list + // element by incrementing the value in the list by 1. + private ArrayList nextUIDs = new ArrayList(CLID.firstCLID.getId()); + + /** Set of extents that are currently modified and need to be stored when + * a transaction commits. + */ + // XXX This relies on the fact that transactions are serialized. Once + // that goes away, index a set of dirtyExtents HashSets by some kind of + // transaction id. + private HashSet dirtyExtents = new HashSet(); + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + /** Logger */ + static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.fostore"); // NOI18N + + /** + * Create a new instance. + * Use this constructor when creating an instance for a brand new + * database (as opposed to an existing database, in which we use the + * Streamable-required default constructor, below). + * @param fodb The FOStoreDatabase instance. + * @exception FOStoreFatalInternalException Thrown when there is an attempt + * to create a second DBInfo within a store. + */ + DBInfo(FOStoreDatabase fodb) { + if (logger.isDebugEnabled()) { + logger.debug("DBInfo: new for " + fodb); // NOI18N + } + this.fodb = fodb; + // Initialize nextUIDs for the reserved CLIDs. + int size = nextCLID.getId(); + for (int i = 0; i < size; i++) { + // FIRST_CLASS_UID number of uid's are reserved per-CLID. + nextUIDs.add(i, new Long(FIRST_CLASS_UID)); + } + } + + void store() throws FOStoreDatabaseException { + fodb.put(dbInfoOID, this); + } + + static DBInfo get(FOStoreDatabase db) throws FOStoreDatabaseException { + DBInfo rc = (DBInfo)db.getIfExists(dbInfoOID); + if (null == rc) { + rc = new DBInfo(db); + rc.fodb = db; + rc.store(); + } + rc.fodb = db; + if (logger.isDebugEnabled()) { + logger.debug("DBInfo.get: " + rc); // NOI18N + } + return rc; + } + + // + // The intent of the next 2 methods is to provide an OID which can be + // used to store information about the class represented by the CLID. + // ActivateClassHandler uses newClassOID to create an OID for storing + // class metadata, GetClassHandler uses getDBClassOID to get that OID. + // + + /** + * Provide a new OID to represent a class. Use this when activating a + * class. + * @return An OID for a class just now known to this store. + */ + OID newClassOID() { + // FIRST_CLASS_UID number of uid's are reserved per-CLID. + nextUIDs.add(nextCLID.getId(), new Long(FIRST_CLASS_UID)); + + OID rc = OID.create(nextCLID, DBCLASS_UID); + + nextCLID = nextCLID.next(); + + if (logger.isDebugEnabled()) { + logger.debug( + "newClassOID: returning; nextCLID now=" + nextCLID); // NOI18N + } + + return rc; + } + + /** + * Provides the OID which represents the given CLID's class. + * @param clid The CLID for which the corresponding OID is needed. + * @return The OID of the CLID. + */ + static OID getDBClassOID(CLID clid) { + return OID.create(clid, DBCLASS_UID); + } + + /** + * Provides the OID which at which is stored the ArrayList of the CLIDs of + * of subclasses of the class corresponding to the CLID. + * @param clid The CLID for which the corresponding OID is needed. + * @return The OID of the ArrayList of CLIDs of the given CLID's + * subclasses. + */ + static OID getSubclassSetOID(CLID clid) { + return OID.create(clid, SUBCLASS_UID); + } + + /** + * Provides the OID which represents extent of instances of objects all of + * which have the given CLID. + * @param clid CLID of extent to return. + * @return OID of the extent of instances of CLID's class. + */ + static OID getExtentOID(CLID clid) { + return OID.create(clid, EXTENT_UID); + } + + /** + * @return Iterator of DBClass objects + */ + Iterator getDBClasses() { + if (logger.isDebugEnabled()) { + logger.debug( + "DBInfo.getDBClasses: first=" + CLID.firstCLID + // NOI18N + ", next=" + nextCLID); // NOI18N + } + return new DBClassIterator(CLID.firstCLID, nextCLID); + } + + class DBClassIterator implements Iterator { + private int current; + private final int finish; + + DBClassIterator(CLID start, CLID finish) { + this.current = start.getId(); + this.finish = finish.getId(); + } + + public boolean hasNext() { + return current < finish; + } + + public Object next() { + Object rc = null; + try { + rc = fodb.get(getDBClassOID(CLID.create(current++, false))); + } catch (FOStoreDatabaseException ex) { + } + return rc; + } + + public void remove() { } + } + + // + // Dirty extent handling + // + + /** + * Marks the given extent as dirty, so that it can later be stored. + */ + boolean makeExtentDirty(DBExtent e) { + return dirtyExtents.add(e); + } + + /** + * Stores all extents that have been marked dirty since the last time this + * method was invoked. + */ + void storeDirtyExtents() throws FOStoreDatabaseException { + for (Iterator i = dirtyExtents.iterator(); i.hasNext();) { + DBExtent dbExtent = (DBExtent)i.next(); + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.commit:" + dbExtent); // NOI18N + } + dbExtent.store(fodb); + } + clearDirtyExtents(); + } + + /** + * Causes this DBInfo to forget about the dirty state of all extents + * marked as dirty since the last time storeDirtyExtents was invoked. + */ + void clearDirtyExtents() { + dirtyExtents.clear(); + } + + /** + * @return Iterator of DBExtent objects + */ + Iterator getExtents() { + if (logger.isDebugEnabled()) { + logger.debug( + "DBInfo.getExtents: first=" + CLID.firstCLID + // NOI18N + ", next=" + nextCLID); // NOI18N + } + return new ExtentIterator(CLID.firstCLID, nextCLID); + } + + class ExtentIterator implements Iterator { + private int current; + private final int finish; + + ExtentIterator(CLID start, CLID finish) { + this.current = start.getId(); + this.finish = finish.getId(); + } + + public boolean hasNext() { + return current < finish; + } + + public Object next() { + Object rc = null; + try { + rc = fodb.get(getExtentOID(CLID.create(current++, false))); + } catch (FOStoreDatabaseException ex) { + } + return rc; + } + + public void remove() { } + } + + /** + * Provide a new OID for the given CLID. Use this when creating an + * instance in the store. The OID will have its CLID part as per the + * given CLID, and its UID part one greater than the last-created + * newInstanceOID. + * @param clid CLID for which a new OID is needed. + * @return An OID for the CLID. + * @exception FOStoreFatalInternalException thrown if the CLID is invalid. + */ + OID newInstanceOID(CLID clid) { + OID rc = null; + int clidIndex = clid.getId(); + + synchronized(nextUIDs) { + if (nextUIDs.size() > clidIndex) { + + // Get the next-uid value, increment by one, store the new + // next-uid. Make an OID to return. + Long UID = (Long)nextUIDs.get(clidIndex); + long uid = UID.longValue(); + if (uid == OID.MAX_UID) { + throw new FOStoreFatalInternalException( + this.getClass(), "newInstance", // NOI18N + msg.msg("ERR_OutOfUIDs", // NOI18N + new Long(OID.MAX_UID))); + } + uid++; + UID = new Long(uid); + nextUIDs.set(clidIndex, UID); + + rc = OID.create(clid, uid); + } else { + throw new FOStoreFatalInternalException( + this.getClass(), "newInstance", // NOI18N + msg.msg("ERR_NoUIDsForCLID", clid)); // NOI18N + } + } + return rc; + } + + /** Returns a human-readable description of this DBInfo. If system + * property "dbinfo.shortname" is true, then the description includes the + * name of the database (e.g. 'foo'), otherwise it includes the complete + * pathname of the database (e.g. '/bleem/foo'). + */ + public String toString() { + StringBuffer sb = new StringBuffer(); + sb.append("DBInfo '"); // NOI18N + String name = fodb.getName(); + // Default is to provide full pathname of database; for testing the + // short name is more appropriate. + if (Boolean.getBoolean("dbinfo.shortname")) { // NOI18N + int pos = name.lastIndexOf(File.separatorChar); + if (pos > 0) { + name = name.substring(pos + 1); + } + } + sb.append(name).append("'\n"); // NOI18N + + sb.append("Next ").append(nextCLID.toString()).append("\n"); // NOI18N + + for (Iterator i = getExtents(); i.hasNext();) { + DBExtent e = (DBExtent)i.next(); + CLID clid = e.getClassCLID(); + Long uid = (Long)nextUIDs.get(clid.getId()); + + sb.append( + " class ").append(e.toString()).append(", "); // NOI18N + sb.append( + "next UID: ").append(uid.toString()).append(".\n"); // NOI18N + } + + return sb.toString(); + } + + // + // Implement Streamable + // + + public DBInfo() { + this(null); + } + + public void write(OutputStream os) throws StorageException { + DataOutputStream dos = new DataOutputStream(os); + + try { + nextCLID.write(dos); + + int size = nextUIDs.size(); + dos.writeInt(size); + for (int i = 0; i < size; i++) { + Long clid = (Long)nextUIDs.get(i); + dos.writeLong(clid.longValue()); + } + } catch (IOException ex) { + throw new StorageIOException(ex); + } + } + + public void read(InputStream is) throws StorageException { + DataInputStream dis = new DataInputStream(is); + try { + nextCLID = CLID.read(dis); + + int size = dis.readInt(); + nextUIDs = new ArrayList(size); + for (int i = 0; i < size; i++) { + nextUIDs.add(i, new Long(dis.readLong())); + } + } catch (IOException ex) { + throw new StorageIOException(ex); + } + } +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteHandler.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteHandler.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteHandler.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteHandler.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,103 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.IOException; + +import org.apache.jdo.util.I18NHelper; + + +/** +* Processes requests to delete objects from the datastore. +* +* @author Dave Bristor +*/ +class DeleteHandler extends RequestHandler { + + /** I18N Support */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + private DeleteHandler(Reply reply, int length, + FOStoreServerConnection con) { + super(reply, length, con); + } + + public static HandlerFactory factory = + new HandlerFactory() { + public RequestHandler getHandler(Reply reply, int length, + FOStoreServerConnection con) { + return new DeleteHandler(reply, length, con); + }}; + + + RequestFinisher handleRequest() + throws IOException, FOStoreDatabaseException { + + if (logger.isDebugEnabled()) logger.debug("DeleteHandler.hR"); //NOI18N + + DataInput in = con.getInputFromClient(); + OID oid = OID.read(in); + boolean optimistic = in.readBoolean(); + + FOStoreDatabase fodb = con.getDatabase(); + + if (logger.isDebugEnabled()) { + logger.debug("DeleteHandler.hR: deleting " + oid + // NOI18N + ", optimistic=" + optimistic); // NOI18N + } + + if (logger.isTraceEnabled()) { + Block block = (Block)fodb.get(oid); + block.dump(); + } + + // Remove instance from database and from its Extent + boolean found = fodb.remove(oid); + + if (found) { + DBInfo dbInfo = fodb.getDBInfo(); + OID extentOID = dbInfo.getExtentOID(oid.getCLID()); + DBExtent dbExtent = (DBExtent)fodb.get(extentOID); + dbExtent.remove(oid); + con.addExtent(dbExtent); + reply.setStatus(Status.OK); + } else { + // Instance to be deleted not in database. If Tx is optimistic, + // it's a consistency failure; if datastore it's a bug. + if (optimistic) { + // XXX when delete verify is added, write the oid there also + oid.write(reply); + reply.setStatus( + Status.OPTIMISTIC, + msg.msg("EXC_DeleteVerifyFailed", oid)); // NOI18N + } else { + + // Should not happen: datastore tx and instance not in store + if (logger.isDebugEnabled()) { + logger.debug( + "DeleteHandler.hR: " + oid + " not in db"); // NOI18N + } + reply.setStatus( + Status.FATAL, + msg.msg("ERR_DatastoreFailed", oid)); // NOI18N + } + } + + return null; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteRequest.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteRequest.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteRequest.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DeleteRequest.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,87 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.IOException; + +import javax.jdo.PersistenceManager; +import javax.jdo.Transaction; +import javax.jdo.JDOHelper; + +import org.apache.jdo.state.StateManagerInternal; + + +/** + * Represents a requests to remove a persistent object in the store. + * + * @author Dave Bristor + */ +// +// This is client-side code. It does not need to live in the server. +// +class DeleteRequest extends AbstractRequest { + /** OID of the instance being deleted. */ + private final OID oid; + + /** Optimistic/datastore state of current transaction. */ + private final boolean optimistic; + + DeleteRequest(StateManagerInternal sm, Message m, FOStorePMF pmf) { + super(sm, m, pmf); + this.oid = (OID)sm.getInternalObjectId(); + PersistenceManager pm = sm.getPersistenceManager(); + Transaction tx = pm.currentTransaction(); + this.optimistic = tx.getOptimistic(); + } + + protected void doRequestBody() throws IOException { + // + // The format of this request is (aside from the request header): + // + // oid: OID + // optimistic: boolean + // numFields: int + // fieldValue: Object... + // + + // XXX Need in optimistic Tx, verify w/ dirtyFields? ; see StoreManger#delete + if (logger.isDebugEnabled()) { + logger.debug("DeleteRequest.dRB: " + oid); // NOI18N + } + oid.write(out); + out.writeBoolean(optimistic); + } + + // + // Methods from Request + // + + /** + * @see Request#handleReply + */ + public void handleReply(Status status, DataInput in, int length) + throws IOException { + + // + // The format of this reply is + // + // empty, that's right, no data needed. + // + if (logger.isDebugEnabled()) logger.debug("DeleteRequest.hR"); // NOI18N + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DoubleTranscriber.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DoubleTranscriber.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DoubleTranscriber.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DoubleTranscriber.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,48 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** +* Transcribes double values. +* +* @author Dave Bristor +*/ +class DoubleTranscriber extends FOStoreTranscriber { + private static DoubleTranscriber instance = new DoubleTranscriber(); + + private DoubleTranscriber() {} + + static DoubleTranscriber getInstance() { + return instance; + } + + void storeDouble(double value, DataOutput out) throws IOException { + out.writeDouble(value); + } + + double fetchDouble(DataInput in) throws IOException { + return in.readDouble(); + } + + void skip(DataInput in) throws IOException { + in.readDouble(); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DummyTranscriber.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DummyTranscriber.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DummyTranscriber.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DummyTranscriber.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,42 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** +* This Transcriber is used to skip managed non-persistent fields. +* Any attempt to use it for fetching or storing a field will +* result in FOStoreAbstractMethodException. +* +* @author Marina Vatkina +*/ +class DummyTranscriber extends FOStoreTranscriber { + private static DummyTranscriber instance = new DummyTranscriber(); + + private DummyTranscriber() {} + + static DummyTranscriber getInstance() { + return instance; + } + + void skip(DataInput in) throws IOException {} + +} + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpHandler.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpHandler.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpHandler.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpHandler.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,261 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.TreeSet; + +import org.apache.jdo.util.I18NHelper; + + +/** +* Process dump requests. A dump request provides information about the +* store. Currently, two options are supported: +* <ul> +* <li>dbInfo: Provide information about all classes stored in the store.</li> +* <li>ClassMetadata: Provide the stored metadata information for the class +* <code>className</code>.</li> +* </ul> +* +* @see org.apache.jdo.impl.fostore.DumpOption +* @author Markus Fuchs +*/ +// This is server-side code. It does not need to live in the client. +class DumpHandler extends RequestHandler { + + /** Maps <code>DumpOptions</code> to + * <code>DumpOptionSubHandlers</code>. The option table must match + * the <code>optionTable</code> in <code>Dumper</code>. + * <p> + * Because the <code>DumpOptionSubHandler</code> are bound to + * the state of the enclosing <code>DumpHander</code> instance, the + * <code>optionTable</code> has to be non-static. */ + private static HashMap optionTable = new HashMap(); + + /** List of results. A SubRequest might report more than one result. */ + private final ArrayList results = new ArrayList(); + + /** Return status. */ + private Status status; + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + /** Initializes the <code>optionTable</code>. + * The option table must match the <code>optionTable</code> in + * <code>Dumper</code>. + * @see Dumper + */ + // Note that there is no entry for DumpOption.CLASS_INSTANCES: that option + // is handled entirely by the Dumper on the client side, with help of + // FOStoreStoreManager.getExtent. + private void initOptionTable() { + optionTable.put(DumpOption.DBINFO, + new DBInfoHandler()); + optionTable.put(DumpOption.CLASS_METADATA, + new ClassMetadataHandler()); + optionTable.put(DumpOption.CLASS_SUBCLASSES, + new ClassSubclassesHandler()); + } + + private DumpHandler(Reply reply, int length, + FOStoreServerConnection con) { + + super(reply, length, con); + initOptionTable(); + } + + public static final HandlerFactory factory = + new HandlerFactory() { + public RequestHandler getHandler(Reply reply, int length, + FOStoreServerConnection con) { + return new DumpHandler(reply, length, con); + }}; + + RequestFinisher handleRequest() + throws IOException, FOStoreDatabaseException { + + FOStoreInput in = con.getInputFromClient(); + FOStoreDatabase db = con.getDatabase(); + + // read arguments + DumpOption option = DumpOption.read(in); + String className = in.readUTF(); + + DumpOptionSubHandler h = + (DumpOptionSubHandler) optionTable.get(option); + if (null == h) { + reply.setStatus(Status.FATAL,msg.msg("ERR_NoSubHandler", option)); // NOI18N + } else { + h.run(db, className); + + int size = results.size(); + reply.writeInt(size); + if (size > 0) { + for (int i = 0; i < size; i++) { + Object o = results.get(i); + if (null != o) { + reply.writeUTF(o.toString()); + } + } + } + reply.setStatus(status); + } + + return null; + } + + /** + * Abstract class for dumping database information. The server creates + * instances of subclasses and then invoke <code>run</code>. Subclasses + * implement <code>run</code> method to do the real work. + */ + abstract class DumpOptionSubHandler { + + /** Must be implemented to dump particular kind of info. + */ + protected abstract void run(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException; + } + + /** + * OptionHandler that dumps DBInfo. + */ + class DBInfoHandler extends DumpOptionSubHandler { + protected void run(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException { + + results.add(db.getDBInfo()); + status = Status.OK; + } + } + + /** + * Abstract OptionHandler that assists in dumping information about + * classes. + */ + abstract class ClassHandler extends DumpOptionSubHandler { + protected void run(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException { + + if (null == className) { + reply.setStatus( + Status.ERROR, + msg.msg("MSG_MissingParameter", className)); //NOI18N + } else { + _run(db, className); + } + } + + DBClass[] getDBClasses(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException { + + DBClass rc[] = null; + + // look for class info in store + DBInfo dbInfo = db.getDBInfo(); + ArrayList found = new ArrayList(); + for (Iterator i = dbInfo.getDBClasses(); i.hasNext();) { + DBClass dbClass = (DBClass)i.next(); + if (className.equals(dbClass.getName())) { + found.add(dbClass); + } + } + int size = found.size(); + if (size > 0) { + rc = new DBClass[size]; + for (int i = 0; i < size; i++) { + rc[i] = (DBClass)found.get(i); + } + } + return rc; + } + + /** Subclasses must implement, to dump their particular kind of info. + */ + abstract void _run(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException; + } + + + /** + * OptionHandler that dumps metadata about a class. + */ + class ClassMetadataHandler extends ClassHandler { + protected void _run(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException { + + DBClass dbClasses[] = getDBClasses(db, className); + for (int i = 0; i < dbClasses.length; i++) { + results.add(dbClasses[i]); + } + status = Status.OK; + } + } + + /** + * OptionHandler that dumps information about the subclasses of a class. + */ + class ClassSubclassesHandler extends ClassHandler { + protected void _run(FOStoreDatabase db, String className) + throws IOException, FOStoreDatabaseException { + + // Sort results in String order. + TreeSet sorted = new TreeSet(); + + DBClass dbClasses[] = getDBClasses(db, className); + if (null == dbClasses || 0 == dbClasses.length){ + results.add( + msg.msg("MSG_DbClassNotFound", className)); // NOI18N + } else { + // For each DBClass known by className, get all of its + // subclasses. + for (int i = 0; i < dbClasses.length; i++) { + String result = null; + CLID clid = dbClasses[i].getCLID(); + OID ssOID = DBInfo.getSubclassSetOID(clid); + SubclassSet sl = (SubclassSet)db.getIfExists(ssOID); + if (null == sl) { + result = msg.msg("MSG_NoSubclasses", className); // NOI18N + } else { + result = msg.msg("MSG_Subclasses", className); // NOI18N + // Get results into the TreeSet + for (Iterator j = sl.iterator(); j.hasNext();) { + CLID subCLID = (CLID)j.next(); + OID subDBClassOID = DBInfo.getDBClassOID(subCLID); + DBClass subDBClass = + (DBClass)db.get(subDBClassOID); + sorted.add("\n\t" + subDBClass.getName()); // NOI18N + } + + // Put sorted subclasses from TreeSet to string + for (Iterator k = sorted.iterator(); k.hasNext();) { + result += (String)k.next(); + } + } + results.add(result); + } + } + status = Status.OK; + } + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpOption.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpOption.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpOption.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpOption.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,134 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.util.HashMap; + +import javax.jdo.JDOUserException; + +import org.apache.jdo.util.I18NHelper; + + +/** Diagnostic code to identify a dump request to the store. Currently, +* there are the following options supported: +* <ul> +* <li>DBINFO: Provide information about all classes in the store.</li> +* <li>CLASS_METADATA: Provide metadata information about a special class.</li> +* <li>CLASS_INSTANCES: List all instances of a special class.</li> +* </ul> +* +* @author Markus Fuchs +*/ +class DumpOption { + /** Value of this DumpOption. */ + private final int value; + + /** String name of this option. */ + private final String name; + + /** Map from name to DumpOption. */ + private static final HashMap options = new HashMap(); + + /** Provide information about all classes in the store. */ + static final DumpOption DBINFO = + new DumpOption(1, "dbInfo"); // NOI18N + + /** Provide metadata information about a particular class.*/ + static final DumpOption CLASS_METADATA = + new DumpOption(2, "classMetadata"); // NOI18N + + /** List all instances of a particular class. */ + static final DumpOption CLASS_INSTANCES = + new DumpOption(3, "classInstances"); // NOI18N + + /** List all subclasses of a particular class. */ + static final DumpOption CLASS_SUBCLASSES = + new DumpOption(4, "classSubclasses"); // NOI18N + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + /** + * Create a DumpOption with the given value and name. + */ + private DumpOption(int value, String name) { + this.value = value; + this.name = name; + options.put(name, this); + } + + /** Provide a DumpOption given a name. */ + static DumpOption forName(String name) { + DumpOption rc = (DumpOption)options.get(name); + if (null == rc) { + throw new JDOUserException( + msg.msg("EXC_BadValue", name)); // NOI18N + } + return rc; + } + + // + // I/O support + // + + /** + * Write this DumpOption's value. + */ + void write(DataOutput out) throws IOException { + out.writeUTF(name); + } + + /** + * Return the instance of a DumpOption that corresponds to the value read + * from the DataInput. + * @throws IOException if there is an IOException reading the value. + * <em>or</em> if the value read does not correspond to a DumpOption. + */ + static DumpOption read(DataInput in) throws IOException { + String optionName = in.readUTF(); + DumpOption rc = forName(optionName); + if (null == rc) { + throw new IOException( + msg.msg("EXC_BadValue", optionName)); // NOI18N + } + return rc; + } + + // + // Override java.lang.Object methods + // + + public String toString() { + return name; + } + + public boolean equals(Object o) { + boolean rc = false; + if ((null != o) && (o instanceof DumpOption)) { + rc = (value == ((DumpOption)o).value); + } + return rc; + } + + public int hashCode() { + // Same as for java.lang.Integer + return value; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpRequest.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpRequest.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpRequest.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/DumpRequest.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,109 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashSet; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import javax.jdo.Extent; +import javax.jdo.JDOHelper; +import javax.jdo.JDOUserException; +import javax.jdo.PersistenceManager; + +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.state.StateManagerInternal; + + +/** + * Represents a request to dump information from the store. + * + * @author Markus Fuchs + */ +// +// This is client-side code. It does not need to live in the server. +// +class DumpRequest extends AbstractRequest { + /** The DumpOption. + */ + private final DumpOption option; + + /** The name of the class queried by this request. + */ + private final String className; + + /** Returned dump information. + */ + private String dump; + + DumpRequest(DumpOption option, String className, Message m, + FOStorePMF pmf) { + + super(m, pmf); + this.option = option; + this.className = className; + } + + protected void doRequestBody() throws IOException { + // + // The format of this request is: + // + // int: option code + // String: className + // + + option.write(out); + out.writeUTF((null != className) ? className : ""); // NOI18N + if (logger.isDebugEnabled()) { + logger.debug("DR.dRB: " + option // NOI18N + + " class=" + className); // NOI18N + } + } + + public void handleReply(Status status, DataInput in, int length) throws IOException { + // + // The format of the reply is: + // int: number of objects (<= one) + // String: information dump + // + // The status might be Status.WARN, in which case either + // * The class to be queried wasn't found. + // * The className parameter was null. + + int count = in.readInt(); + if (logger.isDebugEnabled()) { + logger.debug("DR.hR/0: count=" + count); // NOI18N + } + + StringBuffer results = new StringBuffer(); + for (int i = 0; i < count; i++) { + results.append(in.readUTF()); + } + dump = results.toString(); + + if (logger.isDebugEnabled()) { + logger.debug("DR.hR/1: dump=" + dump); // NOI18N + } + } + + String getDump() { + return dump; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Dumper.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Dumper.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Dumper.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/Dumper.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,280 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.File; +import java.util.HashMap; +import java.util.Iterator; +import java.util.StringTokenizer; + +import javax.jdo.Extent; +import javax.jdo.JDOUserException; +import javax.jdo.PersistenceManager; + +import org.apache.jdo.impl.pm.PersistenceManagerWrapper; +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.util.I18NHelper; + + +/** +* Provides information such as metadata, extents, objects about the store. +* <pre> +* FOStore dumper program usage: +* -DdumpOption=OPTION -DclassNames=CLASSNAMES +* OPTION parameter can be one of the following: +* dbInfo: prints general information about the store. +* classMetadata: prints the metadata for the classes CLASSNAMES. +* classInstances: prints all instances of the classes CLASSNAMES. +* classSubclasses: prints all information about the subclasses +* of the classes CLASSNAMES. +* </pre> +* This class is <code>public</code> because it has a <code>main</code> entry +* point for running as a standalone program. +* +* @author Markus Fuchs +* @author Dave Bristor +*/ +public class Dumper { + + /** Maps <code>DumpOptions</code> to + * <code>DumpOptionSubRequests</code>. The option table must match + * the <code>optionTable</code> in <code>DumpHandler</code>. + * <p> + * Because there is no non-static state to be shared between + * <code>Dumper</code> and the <code>DumpOptionSubRequest</code>s, + * the <code>optionTable</code> can be initilialzed only once. + * @see org.apache.jdo.impl.fostore.DumpOption + */ + private static final HashMap optionTable = new HashMap(); + + private static FOStorePMF pmf; + + /** Class names to dump informations about. */ + private static String classNames; + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + /** + * Initializes the <code>optionTable</code>. + * The option table must match the <code>optionTable</code> in + * <code>DumpHandler</code>. + * @see org.apache.jdo.impl.fostore.DumpHandler + */ + static { + optionTable.put(DumpOption.DBINFO, + new DBInfoRequest()); + optionTable.put(DumpOption.CLASS_METADATA, + new ClassMetadataRequest()); + optionTable.put(DumpOption.CLASS_INSTANCES, + new ClassInstancesRequest()); + optionTable.put(DumpOption.CLASS_SUBCLASSES, + new ClassSubclassesRequest()); + } + + /** + * Given a command line argument that specifies what information + * to dump, gets that information from the database and prints it + * on standard output. + * @param args the command line arguments + */ + public static void main(String args[]) { + + String optionName = System.getProperty("dumpOption"); // NOI18N + if (null == optionName) { + exit(msg.msg("MSG_MissingDumpOption")); // NOI18N + } + classNames = System.getProperty("classNames"); // NOI18N + + try { + DumpOption option = DumpOption.forName(optionName); + + DumpOptionSubRequest r = + (DumpOptionSubRequest)optionTable.get(option); + r.run(); + } catch (Exception ex) { + exit(msg.msg("MSG_DumperException", ex)); // NOI18N + } + } + + /** + * Abstract class for dumping database information. Clients create + * instances of subclasses and then invoke <code>run</code>. Subclasses + * implement <code>dump</code> method to do the real work. + */ + static abstract class DumpOptionSubRequest { + protected PersistenceManager pm; + protected FOStoreStoreManager srm; + protected StringTokenizer st; + + /** Called by clients to cause information to be dumped. + */ + void run() { + try { + setupPMF(); + pm = pmf.getPersistenceManager(); + srm = (FOStoreStoreManager)pmf.getStoreManager(pm); + dump(); + } catch (Exception ex) { + exit(msg.msg("MSG_DumperException", ex)); // NOI18N + } + } + + /** Subclasses must implement, to dump their particular kind of info. + */ + protected abstract void dump(); + } + + /** + * DumpRequest that can dump DBInfo. + */ + static class DBInfoRequest extends DumpOptionSubRequest { + protected void dump() { + println(srm.dump(DumpOption.DBINFO, "")); // NOI18N + } + } + + /** + * Abstract DumpRequest that assists in dumping + * information about classes. + */ + static abstract class ClassRequest extends DumpOptionSubRequest { + protected void dump() { + StringTokenizer st = + new StringTokenizer(classNames, ","); // NOI18N + while (st.hasMoreElements()) { + subDump((String)st.nextElement()); + } + } + + /** Subclasses must implement, to dump their particular kind + * of info. + */ + protected abstract void subDump(String className); + } + + /** + * DumpRequest that dumps metadata about a class. + */ + static class ClassMetadataRequest extends ClassRequest { + protected void subDump(String className) { + println(srm.dump(DumpOption.CLASS_METADATA, className)); + } + } + + /** + * DumpRequest that dumps information about the instances + * of a class. + */ + static class ClassInstancesRequest extends ClassRequest { + protected void subDump(String className) { + int objCount = 0; + Class cls = null; + try { + cls = Class.forName(className); + } catch (ClassNotFoundException ex) { + throw new JDOUserException( + msg.msg("EXC_InstantiateClass", className)); // NOI18N + } + + println("\n" + msg.msg("MSG_ExtentName", className)); // NOI18N + Extent e = pm.getExtent(cls, false); + for (Iterator i = e.iterator(); i.hasNext();) { + Object pc = i.next(); + println("" + pc); // NOI18N + objCount++; + } + println(msg.msg("MSG_ExtentCount", className, // NOI18N + new Integer(objCount))); + } + } + + /** + * DumpRequest that dumps information about the subclasses + * of a class. + */ + static class ClassSubclassesRequest extends ClassRequest { + protected void subDump(String className) { + int objCount = 0; + Class cls = null; + try { + cls = Class.forName(className); + } catch (ClassNotFoundException ex) { + throw new JDOUserException( + msg.msg("EXC_InstantiateClass", className)); // NOI18N + } + + println(srm.dump(DumpOption.CLASS_SUBCLASSES, className)); + } + } + + /** Print an error message and exit. + */ + private static void exit(String message) { + println(message); + usage(); + System.exit(1); + } + + /** Print the usage message on standard output. + */ + private static void usage() { + println(msg.msg("MSG_Usage")); // NOI18N + } + + /** + * Configures a PMF with some basic properties, and creates the + * corresponding database. + */ + private static void setupPMF() throws Exception { + pmf = new FOStorePMF(); + pmf.setConnectionCreate(false); + + pmf.setConnectionUserName(System.getProperty("user", // NOI18N + "fred")); // NOI18N + pmf.setConnectionPassword(System.getProperty("password", // NOI18N + "wombat")); // NOI18N + + // Create url in string form. + String path = ""; // NOI18N + + String dir = System.getProperty("dir"); // NOI18N + if (null == dir) { + dir = System.getProperty("user.dir"); // NOI18N + } + + String name = System.getProperty("name"); // NOI18N + if (null == name) { + name = "FOStoreTestDB"; // NOI18N + } + + path += dir + File.separator; + path += name; + + path = "fostore:" + path; // NOI18N + + pmf.setConnectionURL(path); + } + + /** Print a message on the standard output. + * @param s the message to print. + */ + private static void println(String s) { + System.out.println(s); + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreAbstractMethodException.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreAbstractMethodException.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreAbstractMethodException.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreAbstractMethodException.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,31 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import javax.jdo.JDOFatalInternalException; + +/** + * This exception means that a subclass didn't override a method that it should + * have. When thrown, it means there is an implementation bug. + * + * @author Dave Bristor + */ +class FOStoreAbstractMethodException extends JDOFatalInternalException { + FOStoreAbstractMethodException(String msg) { + super(msg); // NOI18N + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreBtreeStorage.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreBtreeStorage.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreBtreeStorage.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreBtreeStorage.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,142 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.util.HashMap; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.netbeans.mdr.persistence.MOFID; +import org.netbeans.mdr.persistence.ObjectResolver; +import org.netbeans.mdr.persistence.StorageException; +import org.netbeans.mdr.persistence.btreeimpl.btreestorage.BtreeFactory; +import org.netbeans.mdr.persistence.btreeimpl.btreestorage.BtreeStorage; + +/** + * FOStore specific BtreeStorage subclass. This class manages MOFIDs for a + * FOStore datastore. A MOFID consists of two parts: a storageId of type + * String and a serial number of type long. When storing on disk the + * storageId is converted into a number and stored as 16-bit value. Only 48 + * bits of the serial number get represented on disk. FOStore uses the + * serial number to encode the uid part of an OID and the storageId for the + * class id of an OID. The btree class MOFIDInfo converts a MOFID into a + * byte array of 8 bytes that is stored on disk. The two high order bytes + * represent the storageId. Class MOFIDInfo calls method storageIdToNumber + * to convert a String storageId into a number. The remaining 6 bytes + * represent the serial number. + * + * @author Michael Bouschen + * @since 1.1 + * @version 1.1 + */ +public class FOStoreBtreeStorage extends BtreeStorage { + + /** + * Dummy ObjectResolver instance required by BtreeStorage create and + * open methods. + */ + private static final ObjectResolver resolver = new Resolver(); + + /** Prefix for the storageId generated from an class id. */ + private static final String CLID_PREFIX = "FOSTORE_CLID"; + + /** Length of class id prefix. */ + private static final int CLID_PREFIX_LENGTH = 12; + + /** Logger */ + static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.fostore"); // NOI18N + + /** + * Creates a new FOStoreBtreeStorage instance. The constructor creates + * or opens a storage based on the specified argument <code>isNew</code>. + * @param name the name of the storage. + * @param isNew true if the database is being created + */ + public FOStoreBtreeStorage(String name, boolean isNew) + throws StorageException { + super(name); + if (isNew) { + create(true, resolver); + } + else { + open(false, resolver); + } + } + + /** + * Returns Creates a MOFID based on the class id and uid taken from a + * FOStore OID. The storageId of the returned MOFID represents the + * class id and the serial number represents the uid. + * @param clid the class id + * @param uid the unique id + * @return MOFID representing class id and uid taken from FOStore OID. + */ + public MOFID createMOFID(int clid, long uid) { + // Add FIRST_EXTERNAL_ID to avoid clashes with + // internal btree serial numbers + long serialNumber = uid + BtreeFactory.FIRST_EXTERNAL_ID; + // The prefix CLID_PREFIX check whether the storageId denotes a + // fostore class id. Add FIRST_EXTERNAL_CODE to avoid clashes with + // internal btree storageId codes + String storageId = + CLID_PREFIX + (clid + BtreeFactory.FIRST_EXTERNAL_CODE); + return new MOFID(serialNumber, storageId); + } + + /** + * Converts a storageId to an int. If the specified storageId starts + * with CLID_PREFIX, then the storageId represents a class id. In this + * case use the class id as the numeric reresentation. + * @param storageId the storageId as String + * @return the numeric representation of the storageId + */ + public int storageIdToNumber(String storageId) throws StorageException { + if (storageId.startsWith(CLID_PREFIX)) + return Integer.parseInt(storageId.substring(CLID_PREFIX_LENGTH)); + else + return super.storageIdToNumber(storageId); + } + + /** + * Creates a storage id from an int. It returns the FOStore specific + * String representation for a storageId representing a class id. + * @param number the numberic representation of the storageId + * @return the storageId as String + */ + public String numberToStorageId(int number) throws StorageException { + if (number >= BtreeFactory.FIRST_EXTERNAL_CODE) + return CLID_PREFIX + number; + else + return super.numberToStorageId(number); + } + + /** Dummy implementation. */ + static class Resolver implements ObjectResolver { + + /** */ + public Object resolve(String storageID, Object key) { + if (logger.isDebugEnabled()) { + logger.debug("FOStoreBtreeStorage: called Resolver.resolve(" + + storageID + ", " + key + ")"); + } + return new Object(); + } + } +} + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnection.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnection.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnection.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnection.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,82 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +/** + * Represents the connection as seen by the client. This contains two types + * of interface: that used by the ConnectionFactory, and that used by the + * Message. It provides a means for managing the data sent and received + * from the store, as well as for being managed in a pool. + * + * @author Dave Bristor + */ +interface FOStoreClientConnection extends FOStoreConnection { + + /** Connect to the data source. + */ + public void connect() throws IOException; + + /** + * Provides DataInput from which the client can read replies from + * the server. + * @return DataInput from which the client can read replies. + */ + public DataInput getInputFromServer() throws IOException; + + /** + * Indicates that the client has finished writing. The data is sent to the + * server and processed there. + */ + public void sendToStore(byte[] buffer, int start, int length) throws IOException; + + /** + * Put this connection back into the connection pool managed by the + * ConnectionFactory. + */ + public void close() throws IOException; + + /** Set the connection id used to create this connection. This is used + * to determine which connection pool is used. + */ + public void setConnectionId (FOStoreConnectionId connectionId); + + /** Get the connection id used to create this connection. Connections + * are pooled based on this connection id. + */ + public FOStoreConnectionId getConnectionId(); + + /** Set the connection id used to create this connection. This is used + * to determine which connection pool is used. + */ + public void setConnectionFactory (FOStoreConnectionFactory connectionFactory); + + /** Get the connection Factory used to create this connection. Connections + * are pooled based on this connection Factory. + */ + public FOStoreConnectionFactory getConnectionFactory(); + + /** Close the database associated with this connection. In the remote case, + * close the socket. + */ + public void closeDatabase() throws IOException, FOStoreDatabaseException ; + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnectionImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnectionImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnectionImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreClientConnectionImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,152 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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. + */ + +/* + * FOStoreClientConnectionImpl.java + * + * Created on June 7, 2001, 3:17 PM + */ + +package org.apache.jdo.impl.fostore; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.OutputStream; + +import java.net.URLConnection; +import java.net.URL; +import java.net.Socket; + +import java.util.Date; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +/** + * Implementation of the client side of a FOStore connection. + * + * @author Craig Russell + * @version 1.0 + */ +abstract class FOStoreClientConnectionImpl extends URLConnection implements FOStoreClientConnection { + + /** Message to handle connection-to-connection messages (login). + */ + Message message = new Message(); + + FOStoreConnectionFactory connectionFactory; + + FOStoreConnectionId connectionId; + + /** Flag set while logging in. This flag, when set, causes close() to + * retain the connection instead of returning the connection to the pool. + */ + private boolean loggingIn = true; + + /** Logger */ + static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.fostore"); // NOI18N + + /** Creates new FOStoreClientConnectionImpl */ + public FOStoreClientConnectionImpl(URL url) { + super (url); + if (logger.isDebugEnabled()) logger.debug("FOCCI<init>" + // NOI18N + " Host: " + url.getHost() + // NOI18N + " Port: " + url.getPort() + // NOI18N + " Path: " + url.getPath()); // NOI18N + } + + /** + * Return this connection to the connection pool. + */ + public void close() throws IOException { + if (!loggingIn) { + if (logger.isDebugEnabled()) { + logger.debug ("FOCCI.close: closing"); // NOI18N + } + connectionFactory.closeConnection(this); + } else { + if (logger.isDebugEnabled()) { + logger.debug ("FOCCI.close: loggingIn; not closing"); // NOI18N + } + } + } + + /** Log in to the datastore. This will be done for both local and + * remote connections. + */ + protected void login() throws IOException { + String path = localizePath(url.getPath()); + + if (logger.isDebugEnabled()) { + logger.debug("FOCCI:login " + // NOI18N + " Database: " + path + // NOI18N + " User: " + connectionId.getUser() + // NOI18N + " Password: " + connectionId.getPassword() + // NOI18N + " Create: " + connectionId.getCreate()); // NOI18N + } + LoginRequest logreq = + new LoginRequest( + message, connectionFactory.getPMF(), + path, connectionId.getUser(), connectionId.getPassword(), + connectionId.getCreate()); + logreq.doRequest(); + // false => NOT ok to close (this) connection + message.processInStore(this, false); + loggingIn = false; + } + + public void setConnectionFactory(FOStoreConnectionFactory cf) { + this.connectionFactory = cf; + } + + /** Get the connection Factory used to create this connection. Connections + * are pooled based on this connection Factory. + */ + public FOStoreConnectionFactory getConnectionFactory() { + return connectionFactory; + } + + /** Set the connection id used to create this connection. This is used + * to determine which connection pool is used. + */ + public void setConnectionId (FOStoreConnectionId id) { + if (logger.isDebugEnabled()) { + logger.debug("FOCCI.setConnectionId(): " + // NOI18N + " URL: " + id.getUrl() + // NOI18N + " User: " + id.getUser() + // NOI18N + " Password: " + id.getPassword() + // NOI18N + " Create: " + id.getCreate()); // NOI18N + } + this.connectionId = id; + } + + /** Get the connection id used to create this connection. The id + * encapsulates URL, user, and password. Connections + * are pooled based on this connection id. + */ + public FOStoreConnectionId getConnectionId() { + return connectionId; + } + + /** + * @return The path, modified as required for the kind of connection. + */ + abstract protected String localizePath(String path); +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnection.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnection.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnection.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreConnection.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,25 @@ +/* + * Copyright 2005 The Apache Software Foundation. + * + * 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 org.apache.jdo.impl.fostore; + +/** +* Tagging interface at root of all kinds of FOStore connections. +* +* @author Dave Bristor +*/ +interface FOStoreConnection { +}