Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreStoreManager.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreStoreManager.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreStoreManager.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreStoreManager.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,720 @@ +/* + * 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.ArrayList; +import java.util.BitSet; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.io.IOException; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.jdo.Extent; +import javax.jdo.JDOException; +import javax.jdo.JDODataStoreException; +import javax.jdo.JDOFatalInternalException; +import javax.jdo.JDOUserException; +import javax.jdo.JDOFatalUserException; +import javax.jdo.Transaction; +import javax.jdo.spi.JDOImplHelper; +import javax.jdo.spi.PersistenceCapable; +import javax.jdo.spi.StateManager; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.impl.model.java.runtime.RuntimeJavaModelFactory; +import org.apache.jdo.jdoql.BasicQueryResult; +import org.apache.jdo.jdoql.QueryResult; +import org.apache.jdo.jdoql.QueryResultHelper; +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.model.jdo.JDOIdentityType; +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.state.StateManagerInternal; +import org.apache.jdo.store.Connector; +import org.apache.jdo.store.StoreManagerImpl; +import org.apache.jdo.util.I18NHelper; + +// +// Note the exception handling herein; it is intentional: if we catch a +// subclass of JDOException, rethrow it as it is "expected" by calling code, +// but if it is not, then create a subclass of JDOException (as are all +// FOStore exceptions) and throw that. In other words, the intent is that +// only JDOException subclasses be thrown by this class. +// + +/** +* StoreManager represents the datastore to the rest of the JDO components. +* It provides the means to write and read instances, to get the extent of +* classes, and to get the object id for a persistence capable object. +* +* @author Dave Bristor +*/ +class FOStoreStoreManager extends StoreManagerImpl { + private final FOStorePMF pmf; + private final FOStoreConnector connector; + private final RequestFactory rf; + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance( + I18N.NAME, FOStoreStoreManager.class.getClassLoader()); + + /** Logger */ + static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.fostore"); // NOI18N + + /** JDOImplHelper instance. */ + private static final JDOImplHelper jdoImplHelper = + (JDOImplHelper) AccessController.doPrivileged ( + new PrivilegedAction () { + public Object run () { + try { + return JDOImplHelper.getInstance(); + } + catch (SecurityException e) { + throw new JDOFatalUserException (msg.msg( + "ERR_Security", e.getMessage()), e); // NOI18N + } + } + } + ); + + /** RuntimeJavaModelFactory. */ + private static final RuntimeJavaModelFactory javaModelFactory = + (RuntimeJavaModelFactory) AccessController.doPrivileged( + new PrivilegedAction () { + public Object run () { + return RuntimeJavaModelFactory.getInstance(); + } + } + ); + + FOStoreStoreManager(FOStorePMF pmf) { + this.pmf = pmf; + this.connector = new FOStoreConnector(pmf); + this.rf = pmf.getRequestFactory(); + } + + // + // Implement org.apache.jdo.store.StoreManager + // + + /** + * @see org.apache.jdo.store.StoreManager#getConnector + */ + public Connector getConnector() { + return connector; + } + + /** + * @see org.apache.jdo.store.StoreManager#getConnector(String userid, + * String password) + */ + public Connector getConnector(String userid, String password) { + throw new JDOUserException("Not yet implemented"); // NOI18N + } + + + /** + * @see org.apache.jdo.store.StoreManager#insert(BitSet, BitSet, + * StateManagerInternal) + */ + public synchronized int insert( + BitSet loadedFields, BitSet dirtyFields, StateManagerInternal sm) { + + Message message = connector.getMessage(); + try { + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.insert"); // NOI18N + } + + InsertRequest request = rf.getInsertRequest(sm, message, pmf); + request.doRequest(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "insert", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "insert", ex); // NOI18N + } + dirtyFields.xor(dirtyFields); // Clear all bits. + return StateManagerInternal.FLUSHED_COMPLETE; + } + + + /** + * @see org.apache.jdo.store.StoreManager#update(BitSet, BitSet, + * StateManagerInternal) + */ + public synchronized int update( + BitSet loadedFields, BitSet dirtyFields, StateManagerInternal sm) { + + Message message = connector.getMessage(); + try { + UpdateRequest request = + rf.getUpdateRequest(sm, message, pmf, + loadedFields, dirtyFields, optimistic); + request.doRequest(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "update", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "update", ex); // NOI18N + } + dirtyFields.xor(dirtyFields); // Clear all bits. + return StateManagerInternal.FLUSHED_COMPLETE; + } + + + /** + * @see org.apache.jdo.store.StoreManager#verifyFields(BitSet, + * BitSet, StateManagerInternal) + */ + public synchronized int verifyFields( + BitSet ignoredFields, BitSet fieldsToVerify, StateManagerInternal sm) { + + if ( ! verify(sm, true, fieldsToVerify)) { + throw new JDODataStoreException( + msg.msg("EXC_VerifyFields")); // NOI18N + } + fieldsToVerify.xor(fieldsToVerify); // Clear all bits. + return StateManagerInternal.FLUSHED_COMPLETE; + } + + // RESOLVE: Marina, do we need this? @see org.apache.jdo.store.StoreManager#verifyExistence. + /** + * @see org.apache.jdo.store.StoreManager#verifyExistence + */ +// public boolean verifyExistence(StateManagerInternal sm) { +// return verify(sm, false, null, null); +// } + + /** + * @see org.apache.jdo.store.StoreManager#delete(BitSet, BitSet, + * StateManagerInternal) + */ + public synchronized int delete( + BitSet loadedFields, BitSet dirtyFields, StateManagerInternal sm) { + + Message message = connector.getMessage(); + try { + DeleteRequest request = rf.getDeleteRequest(sm, message, pmf); + request.doRequest(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "delete", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "delete", ex); // NOI18N + } + dirtyFields.xor(dirtyFields); + return StateManagerInternal.FLUSHED_COMPLETE; + } + + /** + * @see org.apache.jdo.store.StoreManager#fetch + */ + public synchronized void fetch(StateManagerInternal sm, int fieldNums[]) { + + Message message = connector.getMessage(); + try { + FetchRequest request = rf.getFetchRequest(sm, message, pmf); + request.doRequest(); + connector.flush(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "fetch", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "fetch", ex); // NOI18N + } + } + + /** + * @see org.apache.jdo.store.StoreManager#getExtent + */ + public synchronized Extent getExtent(Class pcClass, boolean subclasses, + PersistenceManagerInternal pm) { + + FOStoreModel model = pmf.getModel(); + Message message = connector.getMessage(); + + // If the instance's class has PC superclasses, we must make sure + // they are activated too. + activateClasses(pcClass, message); + + return new FOStoreExtent(pcClass, subclasses, pm, rf, connector); + } + + /** + * Creates a new object id for the given sm. Delegates implementation to + * #createInternalObjectId(StateManagerInternal sm,Class cls, + * PersistenceManagerInternal pm) + * @see org.apache.jdo.store.StoreManager#createObjectId + */ + public synchronized Object createObjectId(StateManagerInternal sm, + PersistenceManagerInternal pm) { + PersistenceCapable obj = sm.getObject(); + Class cls = obj.getClass(); + OID rc = createInternalObjectId(sm, obj, null, cls, pm); + return rc; + } + + /** + * Creates a new object id for the given class. Binds metadata for the sm + * (i.e., ensures that there is a CLID for instances of the sm's object's + * class). Creates a request in the message that will provide a datastore + * oid for the provisional oid which is returned, but does not interact + * with the store. + * @see org.apache.jdo.store.StoreManager#createObjectId + */ + public synchronized OID createInternalObjectId(StateManagerInternal sm, + PersistenceCapable pc, Object oid, + Class cls, PersistenceManagerInternal pm) { + FOStoreModel model = pmf.getModel(); + Message message = connector.getMessage(); + + // If the instance's class has PC superclasses, we must make sure + // they are activated too. + JDOClass jdoClass = model.getJDOClass(cls); + + // Now we can bind class type to the correct OID instance. + OID rc = model.bind(cls, jdoClass.getIdentityType(), pc, oid, pm, pmf); + + activateClasses(cls, message); + + // If the instance's CLID is provisional, we must activate its class. + CLID clid = rc.getCLID(); + if (clid.isProvisional() && ! message.containsCLID(clid)) { + activateClass(cls, message); + message.addCLID(clid); + } + + try { + CreateOIDRequest request = + rf.getCreateOIDRequest(sm, message, pmf, rc, pm); + request.doRequest(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "createObjectid", ex); // NOI18N + } + return rc; + } + + /** + * Provides a datastore object id. + * If objectId is not provisional, return it. Otherwise, see if we have a + * corresponding datastore objectId and return that if so. If neither of + * those works out, flush the current message which (we hope) will have a + * corresponding CreateObjectIdRequest in it. Then look as before for a + * corresponding datastore objectId in our mapping and return that. If we + * still don't have a correspondance, throw an exception. + * @see org.apache.jdo.store.StoreManager#getExternalObjectId(Object oid, + * PersistenceCapable pc) + */ + public synchronized Object getExternalObjectId(Object objectId, + PersistenceCapable pc) { + Object rc = null; + + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.getEOID given " + objectId); // NOI18N + } + OID oid = (OID)objectId; + if (oid.isProvisional()) { + if (oid.isDataStoreIdentity()) { + oid = pmf.getRealOIDFromProvisional(oid); + + if (null == oid) { + + // Given objectId is provisional, and we have no mapping. + // Flush so that the CreateObjectId requests that are in + // the current message get written to the store, which + // should cause us to get a datastore oid for the given + // provisional oid. + preFlush(); + oid = pmf.getRealOIDFromProvisional((OID)objectId); + if (null == oid) { + throw new JDOUserException( + msg.msg("EXC_UnboundOID"), objectId); // NOI18N + } + } + } else { + // Do flush only: + preFlush(); + } + } + // Always return a copy + rc = oid.getExternalObjectId(pc); + + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.getEOID returning " + rc); // NOI18N + } + + return rc; + } + + /** + * @see org.apache.jdo.store.StoreManager#copyKeyFieldsFromObjectId + */ + public void copyKeyFieldsFromObjectId(StateManagerInternal sm, + Class pcClass) { + OID oid = (OID)sm.getInternalObjectId(); + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.copyKeyFieldsFromObjectId: " + oid); // NOI18N + } + PersistenceManagerInternal pm = sm.getPersistenceManager(); + FOStoreModel model = pmf.getModel(); + JDOClass jdoClass = model.getJDOClass(pcClass); + oid.copyKeyFieldsToPC(sm, pmf, pcClass, + jdoClass.getPrimaryKeyFieldNumbers()); + } + + /** + * @see org.apache.jdo.store.StoreManager#hasActualPCClass + */ + public boolean hasActualPCClass(Object objectId) { + boolean rc = false; + if (objectId instanceof OID) { + rc = ((OID)objectId).isDataStoreIdentity(); + } + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.hasActualPCClass: " + rc); // NOI18N + } + return rc; + } + + /** + * @see org.apache.jdo.store.StoreManager#getInternalObjectId + */ + public synchronized Object getInternalObjectId(Object objectId, + PersistenceManagerInternal pm) { + OID rc = null; + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.getInternalObjectId: " + objectId); // NOI18N + } + if (objectId instanceof OID) { + rc = ((OID)objectId).copy(); + } else { + Class cls = getPCClassForOid(objectId, pm); + rc = createInternalObjectId(null, null, objectId, cls, pm); + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.getInternalObjectId: got=" + rc); // NOI18N + } + } + return rc; + } + + /** + * @see org.apache.jdo.store.StoreManager#getPCClassForOid + */ + public synchronized Class getPCClassForOid(Object objectId, + PersistenceManagerInternal pm) { + Class rc = null; + Message message = connector.getMessage(); + try { + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.getPCClassForOid: " + + objectId.getClass().getName() + objectId); // NOI18N + } + if (!(objectId instanceof OID)) { + Class cls = objectId.getClass(); + rc = pm.loadPCClassForObjectIdClass(cls); + } else { + OID oid = (OID)objectId; + CLID clid = oid.getCLID(); + + FOStoreModel model = pmf.getModel(); + rc = model.getClass(clid); + + if (null == rc) { + if (logger.isDebugEnabled()) { + logger.debug( + "FOSRM.getPCClassForOid: asking store for CLID: " + + clid); // NOI18N + } + // The clid is not known in this JVM, but it might be known + // in the store. Try to get it. + GetClassRequest request = + rf.getGetClassRequest(clid, message, pmf, pm); + try { + request.doRequest(); + connector.flush(); + rc = request.getClassForCLID(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "getPCClassForOid", ex); // NOI18N + } + } + } + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.getPCClassForOid: got " + rc); // NOI18N + } + } catch (ClassCastException ex) { + throw new JDOUserException( + msg.msg("EXC_NotOID"), ex, objectId); // NOI18N + } catch (ClassNotFoundException ex) { + throw new JDOUserException( + msg.msg("EXC_NotOID"), ex, objectId); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "getPCClassForOid", ex); // NOI18N + } + return rc; + } + + /** + * This method returns an object id instance corresponding to the Class + * and String arguments. The String argument might have been the + * result of executing toString on an object id instance. + * @param pcClass the Class of the persistence-capable instance + * @param str the String form of the object id + * @return an instance of the object identity class + */ + public Object newObjectIdInstance (Class pcClass, String str) { + Object rc = null; + FOStoreModel model = pmf.getModel(); + JDOClass jdoClass = model.getJDOClass(pcClass); + switch (jdoClass.getIdentityType()) { + case JDOIdentityType.APPLICATION: + //No need to create an AID here - it will not be used. + rc = jdoImplHelper.newObjectIdInstance(pcClass, str); + break; + case JDOIdentityType.DATASTORE: + rc = new OID(str); + break; + default: + break; + } + return rc; + } + + /** + * Returns a QueryResult instance which is then returned as the result of + * Query.execute(...). This method allows support for datastore specific + * query execution strategies, since each StoreManager can have its own + * implementation of the QueryResult interface. + * For now fostore uses the non optimized BasicQueryResult as QueryResult + * implemenatation. + * @param qrh the helper providing the query tree, the candidates + * and the actual parameters. + * @return a datastore specific query result instance + */ + public QueryResult newQueryResult(QueryResultHelper qrh) { + return new BasicQueryResult(qrh); + } + + // + // Used within FOStore + // + + /** + * Activates this class and all supeclasses. + */ + private void activateClasses(Class cls, Message message) { + FOStoreModel model = pmf.getModel(); + // If the instance's class has PC superclasses, we must make sure + // they are activated too. + JDOClass jdoClass = model.getJDOClass(cls); + JDOClass jdoSuper = jdoClass.getPersistenceCapableSuperclass(); + if (null != jdoSuper) { + ArrayList javaSupers = new ArrayList(); + while (null != jdoSuper) { + Class javaSuper = javaModelFactory. + getJavaClass(jdoSuper.getJavaType()); + javaSupers.add(javaSuper); + jdoSuper = jdoSuper.getPersistenceCapableSuperclass(); + } + + // Activate the superclasses in order from Object on down, so + // that the store can recognize subclasses. + int size = javaSupers.size(); + for (int i = size - 1; i >= 0; i--) { + Class javaSuper = (Class)javaSupers.get(i); + CLID clidSuper = model.getCLID(javaSuper); + if (clidSuper.isProvisional() && + ! message.containsCLID(clidSuper)) { + activateClass(javaSuper, message); + message.addCLID(clidSuper); + } + } + } + + } + /** + * Writes a request to activate the given state manager's class + */ + private void activateClass(Class cls, Message message) { + ActivateClassRequest request = + rf.getActivateClassRequest(cls, message, pmf); + try { + request.doRequest(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "activateClass", ex); // NOI18N + } + } + + /** + * Dumps information about the store. The provided information + * depends on the <code>option</code> parameter. Currently, + * there are the following options supported: + * <ul> + * <li>DBInfo: Provide information about all classes stored in the + * database.</li> + * <li>MetaData: Provide metadata information about the class + * <code>name</code>.</li> + * </ul> + * @param option Dump option, specifies the kind of information. + * @param name Optional fully qualified classname. + * @see org.apache.jdo.impl.fostore.DumpOption + */ + public String dump(DumpOption option, String name) { + Message message = connector.getMessage(); + try { + DumpRequest request = + rf.getDumpRequest(option, name, message, pmf); + request.doRequest(); + connector.flush(); + return request.getDump(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "dump", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + ex.printStackTrace(); + throw new FOStoreFatalInternalException( + getClass(), "dump", ex); // NOI18N + } + } + + /** + * Get instances for oids + * @param oids List of oids + * @param start Starting index within <code>oids</code> of oids whose + * instances are to be returned. + * @param numInstances Number of instances to return. + * @param pm PersistenceManagerInternal on whose behalf the instances are + * being obtained. + * @param cls Candidate Class for which instances are being obtained. + * @return ArrayList of instances corresponding to + * <code>numInstances</code> of oids in the <code>oids</code> parameter, + * starting at <code>start</code>. + */ + synchronized ArrayList getInstances( + ArrayList oids, int start, int numInstances, + PersistenceManagerInternal pm, Class cls) { + + ArrayList rc = null; + Message message = connector.getMessage(); + try { + GetInstancesRequest request = + rf.getGetInstancesRequest(oids, start, numInstances, + message, pm, cls); + request.doRequest(); + connector.flush(); + rc = request.getInstances(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "getInstances", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "getInstances", ex); // NOI18N + } + return rc; + } + + // + // Implementation detail + // + + /** + * Verifies existence or values of a state manager's object in the + * database. + * @param sm The state manager whose object is to be verified. + * @param verifyFields If true, verify values of object, otherwise verify + * only existence (and ignore remaining parameters). + * @param fieldsToVerify Set of fields to be verified against those in the + * database. + * @return true if verify was successful (either by existence of value + * matching as per verifyFields). + */ + private boolean verify(StateManagerInternal sm, + boolean verifyFields, BitSet fieldsToVerify) { + + boolean rc = false; + Message message = connector.getMessage(); + try { + VerifyRequest request = + rf.getVerifyRequest(sm, message, pmf, + verifyFields, fieldsToVerify); + request.doRequest(); + connector.flush(); + rc = request.getVerified(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "verify", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "verify", ex); // NOI18N + } + return rc; //success + } + + /** + * Write a CommitRequest and flush the connector, to cause all + * CreateOid and ActivateClass requests to be committed in the + * database *before* any inserts, updates, or deletes. + */ + protected void preFlush() { + Message message = connector.getMessage(); + CommitRequest request = rf.getCommitRequest(message, pmf); + if (logger.isDebugEnabled()) { + logger.debug("FOSRM.preFlush"); // NOI18N + } + try { + request.setOkToReleaseDatabase(false); + request.doRequest(); + connector.flush(); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + getClass(), "flush", ex); // NOI18N + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "flush", ex); // NOI18N + } + } +}
Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriber.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriber.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriber.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriber.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,193 @@ +/* + * 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 org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.store.Transcriber; + + +// +// A note on Strings and Objects +// +// The JDO spec calls out special treatment for primitives and Strings, +// lumping everything else into the category "Object". For example, +// StateManager has providedStringField(). So, one would think this singling +// out of String as a "primitive Object" would continue here. +// +// We have not done so. The reason is Collections. Primitives are never +// elements of Collections, only Objects. Strings are Objects. To treat +// them as primitives would require special treatment in each of the +// collection transcribers. Rather than do that, we treat Strings as +// Objects. Eventually, Strings get the same treatment as other immutable +// types such as Integer; see ImmutableStringTranscriber. +// + +/** +* FOStoreTranscriber contains methods to transcribe each primitive type, +* but they all throw AbstractMethodError. Subclasses do the actual +* work, implementing methods for one and only one type of data. +* +* @author Dave Bristor +*/ +abstract class FOStoreTranscriber implements Transcriber { + // See ObjectTranscriber's description of getInstance() method. + static final ObjectTranscriber objectTranscriber = + new ObjectTranscriber(); + + // + // Transcriber methods. All are quasi-abstract: they are intended to be + // overridden. + // + + void storeBoolean(boolean value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeBoolean"); // NOI18N + } + + boolean fetchBoolean(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchBoolean"); // NOI18N + } + + + void storeChar(char value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeChar"); // NOI18N + } + + char fetchChar(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchChar"); // NOI18N + } + + + void storeByte(byte value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeByte"); // NOI18N + } + + byte fetchByte(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchByte"); // NOI18N + } + + + void storeShort(short value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeShort"); // NOI18N + } + + short fetchShort(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchShort"); // NOI18N + } + + + void storeInt(int value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeInt"); // NOI18N + } + + int fetchInt(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchInt"); // NOI18N + } + + + void storeLong(long value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeLong"); // NOI18N + } + + long fetchLong(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchLong"); // NOI18N + } + + + void storeFloat(float value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeFloat"); // NOI18N + } + + float fetchFloat(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchFloat"); // NOI18N + } + + + void storeDouble(double value, DataOutput out) throws IOException { + throw new FOStoreAbstractMethodException(getClass().getName() + + ".storeDouble"); // NOI18N + } + + double fetchDouble(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchDouble"); // NOI18N + } + + void skip(DataInput in) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".skip"); // NOI18N + } + + + // + // Note that the signatures and visibilty of the Object-related + // transcribing methods differ from the above. + // + // The publicly visible storeObject requires a PersistenceManagerInternal + // parameter, so that we can get its StoreManager and an OIDs + // corresponding to a Java objects. + // + // The signature of fetchObject takes Object and int parameters so that + // we can support SCO's, which must be created with an owner and field + // number. It takes a PM so that it can create an object from an OID. + // + + int[] storeObject(Object value, FOStoreOutput out, + PersistenceManagerInternal pm) throws IOException { + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeObject"); // NOI18N + } + + protected int[] storeObject(Object value, FOStoreOutput out) + throws IOException { + + throw new FOStoreAbstractMethodException( + getClass().getName() + ".storeObject"); // NOI18N + } + + Object fetchObject(DataInput in, Object owner, int fieldNum, + PersistenceManagerInternal pm) + throws IOException, Exception { + + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchObject"); // NOI18N + } + + protected Object fetchObject(DataInput in, Object owner, int fieldNum) + throws IOException, Exception { + + throw new FOStoreAbstractMethodException( + getClass().getName() + ".fetchObject"); // NOI18N + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriberFactory.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriberFactory.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriberFactory.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreTranscriberFactory.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,90 @@ +/* + * 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.JDOException; + +import org.apache.jdo.store.Transcriber; +import org.apache.jdo.store.TranscriberFactory; + + +/** +* Provides Transcriber instances for FOStore. Note that only one instance of +* any kind of transcriber is ever created. +* +* @author Dave Bristor +*/ +class FOStoreTranscriberFactory implements TranscriberFactory { + // Singleton + private static FOStoreTranscriberFactory instance; + + private static HashMap transcribers = new HashMap(10); + + private FOStoreTranscriberFactory() { + transcribers.put(boolean.class, + new Transcriber[] { BooleanTranscriber.getInstance()}); + transcribers.put(char.class, + new Transcriber[] { CharTranscriber.getInstance()}); + transcribers.put(byte.class, + new Transcriber[] { ByteTranscriber.getInstance()}); + transcribers.put(short.class, + new Transcriber[] { ShortTranscriber.getInstance()}); + transcribers.put(int.class, + new Transcriber[] { IntTranscriber.getInstance()}); + transcribers.put(long.class, + new Transcriber[] { LongTranscriber.getInstance()}); + transcribers.put(float.class, + new Transcriber[] { FloatTranscriber.getInstance()}); + transcribers.put(double.class, + new Transcriber[] { DoubleTranscriber.getInstance()}); + transcribers.put(Object.class, + new Transcriber[] { ObjectTranscriber.getInstance()}); + } + + static FOStoreTranscriberFactory getInstance() { + if (null == instance) { + instance = new FOStoreTranscriberFactory(); + } + return instance; + } + + /** + * Provides a Transcriber for the given class. The result is an array, as + * defined by the interface, but the return here always contains only one + * Transcriber. + * @param cls Class for which a Transcriber is needed. + * @return An array of transcribers; array will contain only one + * Transcriber. + */ + public Transcriber[] getTranscriber(Class cls) { + Transcriber rc[] = null; + if (cls != null) { + rc = (Transcriber[])transcribers.get(cls); + if (null == rc) { // cls not of a primitive + rc = (Transcriber[])transcribers.get(Object.class); + } + } + return rc; + } +} + + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreURLStreamHandler.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreURLStreamHandler.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreURLStreamHandler.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreURLStreamHandler.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,57 @@ +/* + * 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. + */ + +/* + * FOStoreURLStreamHandler.java + * + * Created on June 7, 2001, 7:11 PM + */ + +package org.apache.jdo.impl.fostore; + +import java.net.URLStreamHandler; +import java.net.URLConnection; +import java.io.IOException; + +/** + * Creates connections to databases. + * @author Craig Russell + * @version 1.0 + */ +class FOStoreURLStreamHandler extends URLStreamHandler { + + static FOStoreURLStreamHandler sh = new FOStoreURLStreamHandler(); + + static FOStoreURLStreamHandler getInstance() { + return sh; + } + + /** Creates new FOStoreURLStreamHandler */ + public FOStoreURLStreamHandler() { + } + + protected URLConnection openConnection(java.net.URL url) + throws IOException { + if (url.getHost().length() == 0) { + // local connection + return new FOStoreLocalConnection(url); + } else { + // remote connection + return new FOStoreRemoteConnection(url); + } + } + +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreUnsupportedException.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreUnsupportedException.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreUnsupportedException.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreUnsupportedException.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,34 @@ +/* + * 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.JDOFatalException; + +/** +* This exception means that a FOStore doesn't have support for what is being +* requested. This differs from JDOUnsupportedException, which indicates that +* an optional feature has not been implemented. This is used, for example, to +* indicate that storing of a particular type (e.g. an array of non-PC objects) +* is not supported. +* +* @author Dave Bristor +*/ +class FOStoreUnsupportedException extends JDOFatalException { + FOStoreUnsupportedException(String msg) { + super(msg); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchHandler.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchHandler.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchHandler.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchHandler.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,143 @@ +/* + * 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.Iterator; + +import javax.jdo.JDOUserException; + +import org.apache.jdo.util.I18NHelper; + + +/** +* Process fetch requests. +* +* @author Dave Bristor +*/ +// +// This is server-side code. It does not need to live in the client. +// +class FetchHandler extends RequestHandler { + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + private FetchHandler(Reply reply, int length, + FOStoreServerConnection con) { + + super(reply, length, con); + } + + public static final HandlerFactory factory = + new HandlerFactory() { + public RequestHandler getHandler(Reply reply, int length, + FOStoreServerConnection con) { + return new FetchHandler(reply, length, con); + }}; + + RequestFinisher handleRequest() + throws IOException, FOStoreDatabaseException { + + // XXX TBD Handle numFields and fieldNums. For now, we're expecting + // only an OID, and we return all field values. + + DataInput in = con.getInputFromClient(); + boolean knownclass = in.readBoolean(); + OID oid = OID.read(in); + CLID clid = oid.getCLID(); + + FOStoreDatabase fodb = con.getDatabase(); + Block block = null; + try { + block = (Block)fodb.getIfExists(oid); + if (null == block) { + if (logger.isDebugEnabled()) { + logger.debug("FR.reply: nonexistent: " + oid); // NOI18N + } + + if (knownclass == false) { + long uid = oid.getUID(); + OID tempOid = null; + if (clid.isProvisional()) { + // Retry with the known class id. + if (logger.isDebugEnabled()) { + logger.debug("FH.hR: replace provisional clid..."); // NOI18N + } + clid = fodb.getRealCLIDFromProvisional(clid); + tempOid = OID.create(clid, uid); + block = (Block)fodb.getIfExists(tempOid); + } + if (null == block) { + // Still not found. Now test subclasses. + + if (logger.isDebugEnabled()) { + logger.debug("FH.hR: test subclassess..."); // NOI18N + } + + OID ssOID = DBInfo.getSubclassSetOID(clid); + SubclassSet ss = (SubclassSet)fodb.getIfExists(ssOID); + if (logger.isDebugEnabled()) { + logger.debug("FH.hR: subclassOID: " + ssOID); // NOI18N + } + if (null != ss) { + if (logger.isDebugEnabled()) { + logger.debug("FH.hR: SubclassSet exists for : " + clid); // NOI18N + } + for (Iterator i = ss.iterator(); i.hasNext();) { + CLID subCLID = (CLID)i.next(); + tempOid = OID.create(subCLID, uid); + if (logger.isDebugEnabled()) { + logger.debug("FH.hR: looking for : " + tempOid); // NOI18N + } + block = (Block)fodb.getIfExists(tempOid); + if (block != null) { + if (logger.isDebugEnabled()) { + logger.debug("FH.hR: exists: " + tempOid); // NOI18N + } + + clid = subCLID; + break; + } + } + } + } + } + } + + if (null == block) { + reply.setStatus( + Status.WARN, + msg.msg("EXC_DoesNotExist", oid.toString())); // NOI18N + } else { + if (logger.isTraceEnabled()) { + logger.trace("FR.reply data:"); // NOI18N + block.dump(); + } + reply.write(block.getData()); + reply.writeCLID(clid); + reply.setStatus(Status.OK); + } + } catch (FOStoreDatabaseException ex) { + reply.setStatus(Status.ERROR, ex); + } + + return null; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchRequest.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchRequest.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchRequest.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FetchRequest.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,137 @@ +/* + * 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.JDOUserException; +import javax.jdo.JDOObjectNotFoundException; + +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.state.StateManagerInternal; + + +/** + * Represents a request to read the values of one or more fields for a + * persistent object from the store. + * + * + * @author Dave Bristor + */ +// +// This is client-side code. It does not need to live in the server. +// +class FetchRequest extends AbstractRequest implements FieldRequest { + private final OID oid; + private final Object owner; + private final PersistenceManagerInternal pm; + + FetchRequest(StateManagerInternal sm, Message m, FOStorePMF pmf) { + super(sm, m, pmf); + + this.oid = (OID)sm.getInternalObjectId(); + this.owner = sm; // Owner will be set to StateManagerInternal + this.pm = (PersistenceManagerInternal)sm.getPersistenceManager(); + + if (logger.isDebugEnabled()) { + logger.debug("FetchRequest: " + oid); // NOI18N + } + } + + // + // Methods from AbstractRequest + // + + protected void doRequestBody() throws IOException { + // + // The format of this request is (aside from the request header): + // + // oid: OID + // numFields: int + // fieldNum: int... + // + + out.writeBoolean(pm.getStoreManager().hasActualPCClass(oid)); + oid.write(out); + + // XXX TBD Make use of the fieldNums (right now we fetch all + // fields). This will entail writing more output as per above. + } + + + // + // Methods from Request + // + + public void handleReply(Status status, DataInput in, int length) + throws IOException { + + // + // The format of this reply is + // + // className: String + // fieldsLength: int + // fieldValue: Object... + // numPairs: int + // CLID, classname pairs... + // + // The value types are as per the metadata, and are provided in the + // same order as that in which they were requested. + // + + byte data[] = new byte[length]; + if (logger.isDebugEnabled()) { + logger.debug("FR.hR: reading " + length + " bytes"); // NOI18N + } + in.readFully(data); + + if (status.equals(Status.WARN)) { + String message = in.readUTF(); + throw new JDOObjectNotFoundException(message); + } + + ClassLoader loader = sm.getPCClass().getClassLoader(); + + FieldFetcher ff = + new FieldFetcher(new FOStoreInput(data, 0, length), + pmf.getModel(), + pm, + loader); + ff.fetch(sm, oid); + } + + + // + // Implement FieldRequest + // + + /** + * Determines which fields (at least) will be read from the store. We say + * 'at least' because while we guarantee that the specified fields will be + * read, other fields may be read; this is implementation dependent. + * @param fieldNums Numbers of the fields which are to be read from the + * store. + */ + public void setFieldNums(int fieldNums[]) { } + + /** + * Adds to the set of fields that are to be manipulated. + * @param fieldNum Number of the field to be manipulated. + */ + public void addFieldNum(int fieldNum) { } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldFetcher.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldFetcher.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldFetcher.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldFetcher.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,474 @@ +/* + * 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.JDOFatalUserException; +import javax.jdo.JDOUserException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.model.jdo.JDOField; +import org.apache.jdo.model.jdo.PersistenceModifier; +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.state.StateManagerInternal; +import org.apache.jdo.util.I18NHelper; + +/** +* Extend AbstractFieldManager overriding only fetchABCField methods +* +* @author Dave Bristor +*/ +class FieldFetcher extends AbstractFieldManager { + /** Read values from here. */ + private final FOStoreInput fin; + + /** PM on whose behalf we read */ + private final PersistenceManagerInternal pm; + + private final FOStoreModel model; + + /** ClassLoader to use for loading the class of the instance. */ + private final ClassLoader candidateLoader; + + /** Class of instance being fetched. */ + private Class cls; + + // + // One of the follwing 2 fields, sm and oid, will be set at an entry to + // this object. + // + + // StateManger for which we're reading data. + private StateManagerInternal sm = null; + + // OID for which we're reading data. + private OID oid = null; + + // OID provided for the request. + private OID oldOID = null; + + // Last read field number + private int currNum = 0; + + // Flag that enables actual field skip. + // If set to false only currNum is ignored. + private boolean skip = true; + + /** 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 + + FieldFetcher(FOStoreInput fin, + FOStoreModel model, + PersistenceManagerInternal pm, + ClassLoader candidateLoader) { + + this.fin = fin; + this.model = model; + this.pm = pm; + this.candidateLoader = candidateLoader; + this.skip = true; + } + + /** Called by AID when PK fields are written sequentially + * independent of their actual field numbers. + */ + FieldFetcher(FOStoreInput fin, + FOStoreModel model, + PersistenceManagerInternal pm, + ClassLoader candidateLoader, + boolean skip) { + + this.fin = fin; + this.model = model; + this.pm = pm; + this.candidateLoader = candidateLoader; + this.skip = skip; + } + + // + // Entry points + // + + /** + * Invoke this if you have a StateManagerInternal for the object that + * you're fetching. For example, see FetchRequest.handleReply(). + */ + void fetch(StateManagerInternal sm, OID oid) throws IOException { + this.sm = sm; + this.oldOID = oid; + fetch(); + } + + /** + * Invoke this if you have an OID for the object that you're fetching. + * For example, see GetExtentRequest.handleReply(). + */ + StateManagerInternal fetch(OID oid) throws IOException { + this.oid = oid; + fetch(); + return sm; + } + + + /** + * Fetches data from input, resulting in an PersistenceCapable object + * with state from the datastore. The format of the data is as per that + * described in InsertRequest. + */ + private void fetch() throws IOException { + String className = fin.readUTF(); + FOStoreSchemaUID fsuid = FOStoreSchemaUID.read(fin); + if (logger.isDebugEnabled()) { + logger.debug("FF.fetch/1: className=" + className + // NOI18N + ", fsuid=" + fsuid + ", oid=" + oid); // NOI18N + } + + // Class of the instance that we are loading. + Class instanceClass = null; + + // JDOClass corresponding to instanceClass. + JDOClass jdoClass = null; + + // ClassLoader of the instance we are loading. + ClassLoader loader = null; + + try { + instanceClass = pm.loadClass(className, candidateLoader); + jdoClass = model.getJDOClass(instanceClass); + + FOStoreSchemaUID instanceClassFsuid = + FOStoreSchemaUID.lookup(instanceClass, model); + if ( ! instanceClassFsuid.equals(fsuid)) { + throw new JDOUserException( + msg.msg("EXC_FsuidMismatch", className)); // NOI18N + } + loader = instanceClass.getClassLoader(); + + // If we have an oid, we might not yet have the classname/CLID + // mapping. Make it so. + if (null != oid) { + CLID clid = oid.getCLID(); + if (model.getClass(clid) == null) { + if (logger.isDebugEnabled()) { + logger.debug( + "FF.fetch/1a: putting for " + // NOI18N + instanceClass.getName() + ", " + clid); // NOI18N + } + model.put(instanceClass, clid); + } + } + } catch (ClassNotFoundException ex) { + throw new JDOUserException( + msg.msg("EXC_CannotLoadInstanceClass", className)); // NOI18N + } + + // We need read the CLID/classname pairs *before* reading the data + // which contains fields using those CLID's, so that we can establish + // a mapping that the FieldFetcher (and StateManager) will use to + // create instances of those classes. + synchronized(fin) { + int fieldsLength = fin.readInt(); + int fieldsPos = fin.getPos(); // Save for later + fin.advance(fieldsLength); + + // + // Read the CLID/classname pairs, and make sure that we have + // both loaded the class and mapped the class to the CLID + // + + int size = fin.readInt(); // number of CLID/classname pairs + for (int i = 0; i < size; i++) { + CLID clid = CLID.read(fin); + String fieldClassName = fin.readUTF(); + FOStoreSchemaUID flduid = FOStoreSchemaUID.read(fin); + + Class fieldClass = model.getClass(clid); + + if (logger.isDebugEnabled()) { + logger.debug("FF.fetch/2: fieldClassName=" + // NOI18N + fieldClassName + + ", fieldClass=" + fieldClass + // NOI18N + ", " + clid + // NOI18N + ", flduid=" + flduid); // NOI18N + } + + if (fieldClass != null) { + // The class is already loaded, just do a sanity check. + if (!fieldClassName.equals(fieldClass.getName())) { + throw new FOStoreFatalInternalException( + getClass(), "handleReply", // NOI18N + msg.msg("ERR_ClassMismatch", // NOI18N + className, + fieldClassName, + fieldClass.getName())); + } + } else { + try { + fieldClass = pm.loadClass(fieldClassName, loader); + + // If the FOStoreSchemaUID for fieldClass doesn't + // match flduid, then we've got a structural mismatch + // between the class in the database and the class in + // the current JVM. + if (! + flduid.equals(FOStoreSchemaUID.lookup(fieldClass, model))) { + throw new JDOUserException( + msg.msg( + "EXC_FsuidMismatch", fieldClassName)); // NOI18N + } + + if (logger.isDebugEnabled()) { + logger.debug( + "FF.fetch/3: putting for " + // NOI18N + fieldClass.getName() + + ", " + jdoClass + // NOI18N + ", " + clid); // NOI18N + } + model.put(fieldClass, clid); + } catch (ClassNotFoundException ex) { + throw new JDOUserException( + msg.msg("EXC_CannotLoadFieldClass", // NOI18N + className, fieldClassName)); + } + } + } + + // sm will be null if we were invoked via the "fetch(oid)" entry + // point. In that case, pm.getStateManager(oid) is only safe + // once we have gone through the above CLID/classname mapping. + if (null == sm) { + sm = pm.getStateManager(oid, instanceClass); + sm.setPCClass(instanceClass); // this will be a no-op if sm is replaced above. + } else { + // It may be the case when StateManager did not know the + // actual type of the instance Class (application identity) + // Read the actual CLID from the stream. + CLID newCLID = CLID.read(fin); + if (oldOID != null && !oldOID.isDataStoreIdentity()) { + if (logger.isDebugEnabled()) { + logger.debug( + "FF.fetch: check OID=" + oldOID + " for SM=" + sm); // NOI18N + } + long uid = oldOID.getUID(); + CLID clid = oldOID.getCLID(); + if (!newCLID.equals(clid)) { + FOStorePMF pmf = (FOStorePMF)pm.getPersistenceManagerFactory(); + oldOID.replaceProvisionalOIDWithReal(OID.create(newCLID, uid), null, null); + + if (logger.isDebugEnabled()) { + logger.debug( + "FF.fetch: new OID=" + oldOID + ", SM=" + sm); // NOI18N + } + } + } + sm.setPCClass(instanceClass); // this will be a no-op if sm is replaced above. + } + + // Save this end-of-data position for later use + int endPos = fin.getPos(); + + // Set the stream's position for reading data values, and get + // them. + fin.setPos(fieldsPos); + + // XXX We should be using the field numbers as given to FetchRequest. + int fields[] = jdoClass.getPersistentFieldNumbers(); + int numFields = fields.length; + if (logger.isDebugEnabled()) { + logger.debug( + "FF.fetch/4: numFields=" + numFields); // NOI18N + } + currNum = 0; + cls = sm.getPCClass(); + sm.replace(fields, this); + + fin.setPos(endPos); + } + } + + void setPCClass(Class pcClass) { + cls = pcClass; + } + + public boolean fetchBooleanField(int fieldNum) { + boolean rc = false; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchBoolean(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchBooleanField", ex); // NOI18N + } + return rc; + } + + public char fetchCharField(int fieldNum) { + char rc = ' '; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchChar(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchCharField", ex); // NOI18N + } + return rc; + } + + public byte fetchByteField(int fieldNum) { + byte rc = 0; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchByte(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchByteField", ex); // NOI18N + } + return rc; + } + + public short fetchShortField(int fieldNum) { + short rc = 0; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchShort(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchShortField", ex); // NOI18N + } + return rc; + } + + public int fetchIntField(int fieldNum) { + int rc = 0; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchInt(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchIntField", ex); // NOI18N + } + return rc; + } + + public long fetchLongField(int fieldNum) { + long rc = 0L; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchLong(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchLongField", ex); // NOI18N + } + return rc; + } + + public float fetchFloatField(int fieldNum) { + float rc = 0.0F; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchFloat(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchFloatField", ex); // NOI18N + } + return rc; + } + + public double fetchDoubleField(int fieldNum) { + double rc = 0.0; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchDouble(fin); + } catch (IOException ex) { + throw new FOStoreFatalIOException( + this.getClass(), "fetchDoubleField", ex); // NOI18N + } + return rc; + } + + public String fetchStringField(int fieldNum) { + String rc = ""; // NOI18N + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + // Need to pass all correct parameters as this can be + // a nested request and we don't want to override important + // info with null's. + rc = (String)t.fetchObject(fin, sm, fieldNum, pm); + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + this.getClass(), "fetchStringField", ex); // NOI18N + } + return rc; + } + + public Object fetchObjectField(int fieldNum) { + Object rc = null; + + skipFields(fieldNum); + FOStoreTranscriber t = model.getTranscriber(cls, fieldNum); + try { + rc = t.fetchObject(fin, sm, fieldNum, pm); + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + this.getClass(), "fetchObjectField", ex); // NOI18N + } + return rc; + } + + private void skipFields(int fieldNum) { + if (skip) { + while(currNum < fieldNum) { + FOStoreTranscriber t = model.getTranscriber(cls, currNum); + try { + t.skip(fin); + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + this.getClass(), "skipFields", ex); // NOI18N + } + currNum++; + } + currNum++; // for the next time. + } // do nothing otherwise. + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldRequest.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldRequest.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldRequest.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FieldRequest.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,38 @@ +/* + * 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; + +/** + * Represents a request to manipulate (read or update) the fields of an + * object. + * + * @author Dave Bristor + */ +interface FieldRequest extends Request { + /** + * Indicates which fields are to be manipulated in the object. + * @param fieldNums The set of field numbers indicating the fields that + * are to be manipulated. + */ + public void setFieldNums(int fieldNums[]); + + /** + * Adds to the set of fields that are to be manipulated. + * @param fieldNum Number of the field to be manipulated. + */ + public void addFieldNum(int fieldNum); +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FloatTranscriber.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FloatTranscriber.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FloatTranscriber.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FloatTranscriber.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 float values. +* +* @author Dave Bristor +*/ +class FloatTranscriber extends FOStoreTranscriber { + private static FloatTranscriber instance = new FloatTranscriber(); + + private FloatTranscriber() {} + + static FloatTranscriber getInstance() { + return instance; + } + + void storeFloat(float value, DataOutput out) throws IOException { + out.writeFloat(value); + } + + float fetchFloat(DataInput in) throws IOException { + return in.readFloat(); + } + + void skip(DataInput in) throws IOException { + in.readFloat(); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassHandler.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassHandler.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassHandler.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassHandler.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,95 @@ +/* + * 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 javax.jdo.JDOUserException; + +import org.apache.jdo.util.I18NHelper; + +/** +* Process GetClass requests. +* +* @author Dave Bristor +*/ +// This is server-side code. It does not need to live in the client. +class GetClassHandler extends RequestHandler { + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + private GetClassHandler(Reply reply, int length, + FOStoreServerConnection con) { + + super(reply, length, con); + } + + public static final HandlerFactory factory = + new HandlerFactory() { + public RequestHandler getHandler(Reply reply, int length, + FOStoreServerConnection con) { + return new GetClassHandler(reply, length, con); + }}; + + RequestFinisher handleRequest() + throws IOException, FOStoreDatabaseException { + + DataInput in = con.getInputFromClient(); + FOStoreDatabase db = con.getDatabase(); + CLID clid = CLID.read(in); + + OID oid = db.getDBInfo().getDBClassOID(clid); + if (logger.isDebugEnabled()) { + logger.debug( + "GetClassHandler.hR/0: " + clid + // NOI18N + " " + Tester.toHex(clid.getId(), 8) + ", " + oid + // NOI18N + " " + Tester.toHex(oid.oid, 16)); // NOI18N + } + + FOStoreDatabase fodb = con.getDatabase(); + try { + DBClass dbClass = (DBClass)fodb.getIfExists(oid); + if (null == dbClass) { + reply.setStatus( + Status.ERROR, + msg.msg("EXC_DoesNotExist", oid.toString())); // NOI18N + } else { + String className = dbClass.getName(); + reply.writeUTF(className); + reply.setStatus(Status.OK); + if (logger.isDebugEnabled()) { + logger.debug( + "GetClassHandler.hR/1: " + className); // NOI18N + } + } + + } catch (ClassCastException ex) { + reply.setStatus(Status.ERROR, ex); + } + + return null; + } +} + + + + + + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassRequest.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassRequest.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassRequest.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/GetClassRequest.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,93 @@ +/* + * 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.JDOUserException; + +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.util.I18NHelper; + + +/** + * Represents a request to get the java.lang.Class corresponding to a CLID. + * + * @author Dave Bristor + */ +// +// This is client-side code. It does not need to live in the server. +// +class GetClassRequest extends AbstractRequest { + /** The CLID of the class sought by this request. */ + private final CLID clid; + + /** PersistenceManagerInternal used to load the class. */ + private final PersistenceManagerInternal pm; + + /** The Class sought by this request. */ + private Class classForCLID; + + GetClassRequest(CLID clid, Message m, + FOStorePMF pmf, PersistenceManagerInternal pm) { + super(m, pmf); + this.clid = clid; + this.classForCLID = null; + this.pm = pm; + } + + protected void doRequestBody() throws IOException { + clid.write(out); + if (logger.isDebugEnabled()) { + logger.debug("GetClassRequest.dRB: " + clid); // NOI18N + } + } + + public void handleReply(Status status, DataInput in, int length) + throws IOException { + + String className = in.readUTF(); + if (logger.isDebugEnabled()) { + logger.debug("GetClassRequest.hR: className=" + className // NOI18N + + " status=" + status); // NOI18N + } + // className is valid if not empty and request succeeded. + if (null != className + && className.length() > 0 + && Status.OK.equals(status)) { + + try { + classForCLID = pm.loadClass(className, null); + // Bind in the metadata + FOStoreModel model = pmf.getModel(); + model.put(classForCLID, clid); + + if (logger.isDebugEnabled()) { + logger.debug("GetClassRequest.hR: classForCLID=" + classForCLID); // NOI18N + } + } catch (ClassNotFoundException ex) { + throw new JDOUserException( + msg.msg("EXC_NoClassForCLID", clid, ex)); // NOI18N + } + } + } + + Class getClassForCLID() { + return classForCLID; + } +}