Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLocalConnection.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLocalConnection.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLocalConnection.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLocalConnection.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.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.net.URL; +import java.net.URLConnection; + +import javax.jdo.JDOUserException; + +/** +* Implements the client and server/store connections for the case in which +* the client and store are running in the same address space. +* +* @author Dave Bristor +*/ +class FOStoreLocalConnection extends FOStoreClientConnectionImpl { + + /** The server that implements the requests + */ + private FOStoreServerConnection server = new FOStoreServerConnectionImpl(); + + /** + * Provides a connection to the database, using the URL support in + * the superclass. + */ + FOStoreLocalConnection(URL url) { + super(url); + } + + /** + * @see FOStoreClientConnection#getInputFromServer + */ + public DataInput getInputFromServer() throws IOException { + return server.getOutputFromServer(); + } + + /** Write bytes to the store. The data is used to construct a FOStoreInput + * for the server to use; then the server is called to process the requests. + */ + public void sendToStore(byte[] buffer, int offset, int length) throws IOException { + if (logger.isDebugEnabled()) logger.debug("FOLC.wTS: " + // NOI18N + (length - offset)); + server.setClientInput (new FOStoreInput (buffer, offset, length)); + server.processRequests(); + } + + /** This connects to the data store, and verifies the user name and password.. + */ + public void connect() throws IOException { + login(); + } + + /** Close the database associated with this connection. This closes the local + * server, which causes the remote database to be closed. + */ + public void closeDatabase() throws FOStoreDatabaseException { + server.closeDatabase(); + } + + /** + * @return The path as given. + */ + protected String localizePath(String path) { + return path; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLoginException.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLoginException.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLoginException.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreLoginException.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 javax.jdo.JDOFatalUserException; + +import org.apache.jdo.util.I18NHelper; + + +/** +* This is an exception which _should_ never be thrown, as it indicates an +* error in the implementation, such as a bug that has been found. +* +* @author Dave Bristor +*/ +public class FOStoreLoginException extends JDOFatalUserException { + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + /** + * @param nested Exception which caused failure + * thrown. + */ + FOStoreLoginException(String dbname, String user, Exception nested) { + super(msg.msg("EXC_LoginFailed", dbname, user), nested); // NOI18N + } +} + Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreModel.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreModel.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreModel.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreModel.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,271 @@ +/* + * 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 java.util.Iterator; +import java.util.Map; +import java.util.Set; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.jdo.JDOFatalInternalException; + +import javax.jdo.spi.PersistenceCapable; + +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.model.ModelException; +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.model.jdo.JDOField; +import org.apache.jdo.model.jdo.JDOIdentityType; +import org.apache.jdo.model.jdo.JDOModel; +import org.apache.jdo.pm.PersistenceManagerFactoryInternal; +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.util.I18NHelper; + +/** +* Provides model information required by fostore: mapping between CLID's and +* the java.lang.Class's. +* +* @author Dave Bristor +*/ +class FOStoreModel { + // Maps from java.lang.Class to CLID. + private HashMap clids = new HashMap(); + + /** Maps from provisional CLID's to java.lang.Class's. See updateCLID + * and getClass. + */ + private HashMap provisionalCLIDs = new HashMap(); + + /** Map from jdoClass to an array of FOStoreTranscribers. */ + private final HashMap transcribers = new HashMap(); + + /** Convenience; so that we don't have to getInstance() all the time. */ + // XXX We may want to rethink how transcribers are accessed. + private final FOStoreTranscriberFactory transcriberFactory = + FOStoreTranscriberFactory.getInstance(); + + /** RuntimeJavaModelFactory. */ + private static final RuntimeJavaModelFactory javaModelFactory = + (RuntimeJavaModelFactory) AccessController.doPrivileged( + new PrivilegedAction () { + public Object run () { + return RuntimeJavaModelFactory.getInstance(); + } + } + ); + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance( + I18N.NAME, FOStoreModel.class.getClassLoader()); + + /** Logger */ + static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.fostore"); // NOI18N + + /** Constructor */ + FOStoreModel() { } + + /** + * Provides the class id for the given class. + * @param cls The class for which the corresponding class id is needed. + * @return CLID for the given class, or null if there is no metadata for + * that class. + */ + CLID getCLID(Class cls) { + // First check if cls has a well-known CLID. If not, get metadata for + // cls and get the CLID for that. If still no CLID, create one and map + // it in the clids table. + CLID rc = CLID.getKnownCLID(cls); + if (null == rc) { + synchronized(clids) { + rc = (CLID)clids.get(cls); + if (null == rc) { + rc = CLID.createProvisional(); + clids.put(cls, rc); + if (logger.isDebugEnabled()) { + logger.debug( + "FOM.getCLID (new): " + cls + " -> " + rc); // NOI18N + } + } + } + } + return rc; + } + + /** + * Add a mapping from ClassMetaData to CLID. + */ + synchronized void put(Class cls, CLID clid) { + clids.put(cls, clid); + } + + /** + * Causes the given class mapped to an OID. + * @param cls Class to be mapped. + * @param type JDOIdentityType as an int. + * @param pc PersistenceCapable instance to copy fields from if available. + * @param oid Object Id instance to copy fields from if available. + * @param pm PersistenceManagerInternal that requested the operation. + * @param pmf FOStorePMF that requested the operation. + * @return ObjectId corresponding to given class. + */ + OID bind(Class cls, int type, PersistenceCapable pc, + Object oid, PersistenceManagerInternal pm, FOStorePMF pmf) { + OID rc = null; + switch (type) { + case JDOIdentityType.APPLICATION: + rc = AID.create(cls, pc, oid, pm, pmf); + break; + case JDOIdentityType.DATASTORE: + CLID clid = getCLID(cls); + rc = OID.create(clid); + break; + default: + break; + } + return rc; + } + + /** + * Changes the class id by which this metadata is known. + * @param pCLID The class id by which the class was previously known. + * @param rCLID The class id by which the class should be known from now + * on in this JVM. + */ + void updateCLID(CLID pCLID, CLID rCLID) { + Map.Entry entry = getEntry(pCLID); + if (null != entry) { + entry.setValue(rCLID); + if (null == provisionalCLIDs.get(pCLID)) { + Class cls = (Class)entry.getKey(); + provisionalCLIDs.put(pCLID, cls); + } + } + } + + /** + * Return the class corresponding to the given CLID. + * @param clid The CLID for which a class is wanted. + * @return The java.lang.Class corresponding to the given CLID, or null if + * none is found. + */ + Class getClass(CLID clid) { + Class rc = null; + Map.Entry entry = getEntry(clid); + if (null != entry) { + rc = (Class)entry.getKey(); + } + + // It is possible we did not find a mapping. This can be the case if, + // for example, 2 objects are created, and one is stored but not the + // other. The act of storing one will update the clids table via + // updateCLID. So we have to look in this other table. + if (null == rc && clid.isProvisional()) { + rc = (Class)provisionalCLIDs.get(clid); + } + return rc; + } + + + // Provide the entry which represents the Class - CLID mapping. While + // this may seem time-wise expensive, we don't expect there to be all + // *that* many classes (O(100)) per JVM. + synchronized Map.Entry getEntry(CLID clid) { + Map.Entry rc = null; + Set entries = (Set)clids.entrySet(); + for (Iterator i = entries.iterator(); i.hasNext();) { + Map.Entry entry = (Map.Entry)i.next(); + CLID aCLID = (CLID)entry.getValue(); + if (clid.equals(aCLID)) { + rc = entry; + break; + } + } + return rc; + } + + // + // Provide access to the JDOModel + // + + /** @param c Class whose corresponding JDOClass is needed. + * @return The JDOClass for the given class. + */ + JDOClass getJDOClass(Class c) { + if (logger.isDebugEnabled()) { + logger.debug("FOM.getJDOClass for " + c.getName()); // NOI18N + } + return javaModelFactory.getJavaType(c).getJDOClass(); + } + + /** Provides a transcriber for the field in the given JDOClass indicated + * by fieldNum. + * @param c JDOClass for which a transcriber is needed. + * @param fieldNum The absolute fieldNumber in the class modeled by + * jdoClass that is to be transcribed. + * @return a FOStoreTranscriber appropriate for the type of field in the + * class modeled by field fieldNum in the class corresponding to + * jdoClass. + */ + FOStoreTranscriber getTranscriber(Class c, int fieldNum) { + FOStoreTranscriber t[] = + (FOStoreTranscriber[])transcribers.get(c); + if (null == t) { + // Create transcribers for jdoClass + JDOClass jdoClass = getJDOClass(c); + // Use managed fields here to preserve correct fieldNum's. + JDOField fields[] = jdoClass.getManagedFields(); + int length = fields.length; + t = new FOStoreTranscriber[length]; + + for (int i = 0; i < length; i++) { + if (fields[i].isPersistent()) { + t[i] = (FOStoreTranscriber)transcriberFactory.getTranscriber( + javaModelFactory.getJavaClass(fields[i].getType()))[0]; + } else { + t[i] = DummyTranscriber.getInstance(); + } + } + transcribers.put(c, t); + } + return t[fieldNum]; + } + + // + // Debug support + // + + void print(Object o) { + print (o.getClass()); + } + + void print(Class c) { + JDOModel m = null; + try { + ClassLoader cl = c.getClassLoader(); + m = javaModelFactory.getJavaModel(cl).getJDOModel(); + org.apache.jdo.impl.model.jdo.util.PrintSupport.printJDOModel(m); + } catch (Exception ex) { + System.out.println("Cannot print model"); // NOI18N + } + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreOutput.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreOutput.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreOutput.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreOutput.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,244 @@ +/* + * 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.DataOutput; +import java.io.DataOutputStream; +import java.io.IOException; + +import org.apache.jdo.util.I18NHelper; + + +/** +* Extend ByteArrayOutputStream so that we can get ahold of the byte array +* and current position, and can make sure we have enough space to write an +* object. We also allow getting and changing the current position. Also, +* implement DataOutput so that we can write easily to this output. +* +* @author Dave Bristor +*/ +class FOStoreOutput implements DataOutput { + // Once closed, no more writing allowed. + private boolean closed = false; + + private final LocalByteArrayOutputStream stream; + private final DataOutputStream dos; + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME); + + FOStoreOutput() { + stream = new LocalByteArrayOutputStream(); + dos = new DataOutputStream(stream); + } + + /** Close the stream. The stream can no longer be written. + */ + public void close() { + closed = true; + } + + /** Reset the stream. Discard the current contents, and reset the count + * to 0 and the current position to 0. The current buffer is retained. + */ + public void reset() { + stream.reset(); + } + + // In a simpler world, FOStoreOutput would extend ByteArrayOutputStream + // and implement DataOutput. However. The creators of the early Java + // classes wisely noted that, in ByteArrayOutputStream, the write methods + // could not throw IOException, after all, there's no I/O happening. Of + // course, with DataOutput, you never know what's behind the scenes, so + // it's write methods *do* throw IOException. Since we need the + // functionality of both, and these are in conflice, we cannot both + // extend ByteArrayOutputStream *and* implement DataOutput. So we + // implement DataOutput and delegate to this extension. + // + class LocalByteArrayOutputStream extends ByteArrayOutputStream { + LocalByteArrayOutputStream() { + super(); + } + + byte[] getBuf() { + return buf; + } + + int getCurrentPosition() { + return count; + } + + void seek(int pos) { + if (pos < 0 || pos > buf.length) { + throw new FOStoreFatalInternalException( + this.getClass(), "seek", // NOI18N + msg.msg("ERR_InvalidSeekPos", // NOI18N + new Integer(pos), new Integer(buf.length))); + } + this.count = pos; + } + } + + /** + * Provides no-copy access to the buffer. + * @return The byte array representing this stream. Not a copy. + */ + byte[] getBuf() { + return stream.getBuf(); + } + + // + // A common need of RequestHandlers is to write a nonsense number, which + // is later filled in with a count or length (etc.) appropriate to the + // reply's acutal data. These help do that. Use them instead of + // getPos/setPos, if/when you can. + // + // This is easy to do by hand, but I've burned myself too many times + // by being imprecise when doing it that way! + // + + /** + * Write a nonsense int value at the current position, and return that + * position for later use with endStash + * @return Position in this output for later use in writing a 'real' + * value. + * @see #endStash + */ + int beginStash() throws IOException { + int rc = getPos(); + writeInt(0xbadbad10); + return rc; + } + + /** + * Write the given value at the given position, and reset the position to + * what it was before the write occurred. + * @param value Value to be written + * @param pos Position in this output at which value is to be written + * @see #beginStash + */ + void endStash(int value, int pos) throws IOException { + int savedPos = getPos(); + setPos(pos); + writeInt(value); + setPos(savedPos); + } + + /** + * Provides the stream's current writing position. + * @return The current writing position of the stream. + */ + int getPos() { + return stream.getCurrentPosition(); + } + + /** + * Allows for setting the current writing position. + * @param pos Position at which future write operations will take + * place. + */ + void setPos(int pos) throws IOException { + stream.seek(pos); + } + + // + // Implement DataOutput by forwarding onto our private DataOutputStream + // + + public void write(byte[] b) throws IOException { + assertNotClosed(); + dos.write(b); + } + + public void write(int b) throws IOException { + assertNotClosed(); + dos.write(b); + } + + public void write(byte[] b, int off, int len) throws IOException { + assertNotClosed(); + dos.write(b, off, len); + } + + public void writeBoolean(boolean v) throws IOException { + assertNotClosed(); + dos.writeBoolean(v); + } + + public void writeByte(int v) throws IOException { + assertNotClosed(); + dos.writeByte(v); + } + + public void writeBytes(String s) throws IOException { + assertNotClosed(); + dos.writeBytes(s); + } + + public void writeChar(int v) throws IOException { + assertNotClosed(); + dos.writeChar(v); + } + + public void writeChars(String s) throws IOException { + assertNotClosed(); + dos.writeChars(s); + } + + public void writeDouble(double v) throws IOException { + assertNotClosed(); + dos.writeDouble(v); + } + + public void writeFloat(float v) throws IOException { + assertNotClosed(); + dos.writeFloat(v); + } + + public void writeInt(int v) throws IOException { + assertNotClosed(); + dos.writeInt(v); + } + + public void writeLong(long v) throws IOException { + assertNotClosed(); + dos.writeLong(v); + } + + public void writeShort(int v) throws IOException { + assertNotClosed(); + dos.writeShort(v); + } + + public void writeUTF(String str) throws IOException { + assertNotClosed(); + dos.writeUTF(str); + } + + // + // Private implementation methods + // + + private void assertNotClosed() { + if (closed) { + throw new FOStoreFatalInternalException( + getClass(), "assertNotClosed", // NOI18N + msg.msg("ERR_Closed")); // NOI18N + } + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMF.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMF.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMF.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMF.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,800 @@ +/* + * 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.PrintWriter; +import java.io.Externalizable; +import java.io.IOException; +import java.io.ObjectOutputStream; +import java.util.Enumeration; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.WeakHashMap; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import javax.naming.NamingException; +import javax.naming.Reference; +import javax.naming.Referenceable; +import javax.naming.StringRefAddr; + +import javax.jdo.JDOException; +import javax.jdo.JDOFatalException; +import javax.jdo.PersistenceManager; +import javax.jdo.spi.PersistenceCapable; + +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.impl.pm.PersistenceManagerFactoryImpl; +import org.apache.jdo.impl.pm.PersistenceManagerImpl; +import org.apache.jdo.model.jdo.JDOClass; +import org.apache.jdo.pm.PersistenceManagerFactoryInternal; +import org.apache.jdo.pm.PersistenceManagerInternal; +import org.apache.jdo.store.StoreManager; +import org.apache.jdo.store.TranscriberFactory; +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. +// + +/** +* The File/Object Store's implementation of a PersistenceManagerFactory. +*

+* This class is public so that clients can create instances of it +* with new. +* +* @author Dave Bristor +*/ +public class FOStorePMF + extends PersistenceManagerFactoryImpl + implements Externalizable, Referenceable +{ + /** + * StoreManagers provided by this PMF, one per-PM. + */ + private transient final HashMap storeManagers = new HashMap(); + + /** + * Map provisional id's that were created on behalf of this PMF to the + * real id's that have been returned by various StoreManager instances + * that are bound to this PMF. + */ + private transient final WeakHashMap provisionalOIDs = new WeakHashMap(); + + // ConnectionFactory associated with this PMF. + private transient FOStoreConnectionFactory cf; + + /** Model associated with this PMF. */ + private transient final FOStoreModel model = new FOStoreModel(); + + /** Flag to tell whether to create. This is not a JDO property. + */ + private boolean create; + + /** The Properties instance from which this PersistenceManagerFactory + * was configured. This is the key into the Properties/PersistenceManagerFactory + * map. + */ + private Properties configuredFrom = null; + + /** RuntimeJavaModelFactory. */ + private static final RuntimeJavaModelFactory javaModelFactory = + (RuntimeJavaModelFactory) AccessController.doPrivileged( + new PrivilegedAction () { + public Object run () { + return RuntimeJavaModelFactory.getInstance(); + } + } + ); + + /** I18N support. */ + private static final I18NHelper msg = I18NHelper.getInstance( + I18N.NAME, FOStorePMF.class.getClassLoader()); + + /** Logger */ + static final Log logger = LogFactory.getFactory().getInstance( + "org.apache.jdo.impl.fostore"); // NOI18N + + /** JNDI property type + */ + static final String addrType = + "Serialized-org.apache.jdo.impl.fostore.FOStorePMF"; // NOI18N + + /** Supported list of options for this implementation. + */ + private final String[] optionArray = new String[] { + "javax.jdo.option.TransientTransactional", // NOI18N + "javax.jdo.option.NontransactionalRead", // NOI18N + "javax.jdo.option.NontransactionalWrite", // NOI18N + "javax.jdo.option.RetainValues", // NOI18N + "javax.jdo.option.Optimistic", // NOI18N + "javax.jdo.option.ApplicationIdentity", // NOI18N + "javax.jdo.option.DatastoreIdentity", // NOI18N +// "javax.jdo.option.NonDatastoreIdentity", // NOI18N + "javax.jdo.option.ArrayList", // NOI18N + "javax.jdo.option.HashMap", // NOI18N + "javax.jdo.option.Hashtable", // NOI18N + "javax.jdo.option.LinkedList", // NOI18N + "javax.jdo.option.TreeMap", // NOI18N + "javax.jdo.option.TreeSet", // NOI18N + "javax.jdo.option.Vector", // NOI18N +// "javax.jdo.option.Map", // NOI18N +// "javax.jdo.option.List", // NOI18N + "javax.jdo.option.Array", // NOI18N + "javax.jdo.option.NullCollection", // NOI18N + "javax.jdo.query.JDOQL" // NOI18N + }; + + /** Properties accessors hash map for fostore-specific properties. + */ + protected static HashMap fostorePropsAccessors = new HashMap(3); + + /** + * Mapping of supported java.util classes to the tracked + * SCO classes in org.apache.jdo.impl.sco package + */ + private static HashMap trackedClasses = new HashMap(); + + /** Initialize fostorePropsAccessors. + */ + // XXX Jikes bug + // If this is protected, FOStorePMF.initPropsAccessors cannot invoke it, + // due to a bug in jikes (http://www-124.ibm.com/developerworks/bugs/?func=detailbug&bug_id=213&group_id=10) + //protected static void initPropsAccessors() { + // + public static void initPropsAccessors() { + PersistenceManagerFactoryImpl.initPropsAccessors(); + if (fostorePropsAccessors.size() != 0) + return; + synchronized (fostorePropsAccessors) { + if (fostorePropsAccessors.size() != 0) { + return; + } + fostorePropsAccessors.put( + "org.apache.jdo.ConnectionCreate", // NOI18N + new PMFAccessor() { + public String get(PersistenceManagerFactoryImpl pmf) { return new Boolean(((FOStorePMF)pmf).getConnectionCreate()).toString(); } + public String getNonDefault(PersistenceManagerFactoryImpl pmf) { return (!((FOStorePMF)pmf).getConnectionCreate())?null:"true"; } // NOI18N + public String getDefault() { return "false"; } // NOI18N + public void set(PersistenceManagerFactoryImpl pmf, String s) { ((FOStorePMF)pmf).setConnectionCreate(Boolean.valueOf(s).booleanValue()); } + }); + fostorePropsAccessors.put( + "org.apache.jdo.option.QueryTimeout", // NOI18N + new PMFAccessor() { + public String get(PersistenceManagerFactoryImpl pmf) { return Integer.toString(pmf.getQueryTimeout()); } + public String getNonDefault(PersistenceManagerFactoryImpl pmf) { return (pmf.getQueryTimeout()==0)?null:Integer.toString(pmf.getQueryTimeout()); } + public String getDefault() { return "0"; } // NOI18N + public void set(PersistenceManagerFactoryImpl pmf, String s) { pmf.setQueryTimeout(toInt(s)); } + }); + fostorePropsAccessors.put( + "org.apache.jdo.option.UpdateTimeout", // NOI18N + new PMFAccessor() { + public String get(PersistenceManagerFactoryImpl pmf) { return Integer.toString(pmf.getUpdateTimeout()); } + public String getNonDefault(PersistenceManagerFactoryImpl pmf) { return (pmf.getUpdateTimeout()==0)?null:Integer.toString(pmf.getUpdateTimeout()); } + public String getDefault() { return "0"; } // NOI18N + public void set(PersistenceManagerFactoryImpl pmf, String s) { pmf.setUpdateTimeout(toInt(s)); } + }); + } + } + + /** Return the FOStore-specific accessors (the + * properties that are not in the JDO specification). + * @return the hash map of FOStore accessors + */ + protected HashMap getLocalAccessors() { + initPropsAccessors(); + return fostorePropsAccessors; + } + + /** Initialize trackedClasses. + */ + private void initTrackedClasses() { + if (trackedClasses.size() != 0) { + return; + } + synchronized (trackedClasses) { + if (trackedClasses.size() != 0) { + return; + } + + // We will need to compare equals to ensure that we do not override + // user's defined classes: + + // java.util.Date and java.sql classes: + trackedClasses.put(java.util.Date.class, + org.apache.jdo.impl.sco.Date.class); + trackedClasses.put(org.apache.jdo.impl.sco.Date.class, + org.apache.jdo.impl.sco.Date.class); + trackedClasses.put(java.sql.Date.class, + org.apache.jdo.impl.sco.SqlDate.class); + trackedClasses.put(org.apache.jdo.impl.sco.SqlDate.class, + org.apache.jdo.impl.sco.SqlDate.class); + trackedClasses.put(java.sql.Time.class, + org.apache.jdo.impl.sco.SqlTime.class); + trackedClasses.put(org.apache.jdo.impl.sco.SqlTime.class, + org.apache.jdo.impl.sco.SqlTime.class); + trackedClasses.put(java.sql.Timestamp.class, + org.apache.jdo.impl.sco.SqlTimestamp.class); + trackedClasses.put(org.apache.jdo.impl.sco.SqlTimestamp.class, + org.apache.jdo.impl.sco.SqlTimestamp.class); + + // java.util.Set + trackedClasses.put(java.util.HashSet.class, + org.apache.jdo.impl.sco.HashSet.class); + trackedClasses.put(java.util.AbstractSet.class, + org.apache.jdo.impl.sco.HashSet.class); + trackedClasses.put(java.util.Set.class, + org.apache.jdo.impl.sco.HashSet.class); + trackedClasses.put(org.apache.jdo.impl.sco.HashSet.class, + org.apache.jdo.impl.sco.HashSet.class); + + // java.util.List + trackedClasses.put(java.util.ArrayList.class, + org.apache.jdo.impl.sco.ArrayList.class); + trackedClasses.put(java.util.AbstractList.class, + org.apache.jdo.impl.sco.ArrayList.class); + trackedClasses.put(java.util.List.class, + org.apache.jdo.impl.sco.ArrayList.class); + trackedClasses.put(java.util.AbstractCollection.class, + org.apache.jdo.impl.sco.ArrayList.class); + trackedClasses.put(java.util.Collection.class, + org.apache.jdo.impl.sco.ArrayList.class); + trackedClasses.put(org.apache.jdo.impl.sco.ArrayList.class, + org.apache.jdo.impl.sco.ArrayList.class); + + // java.util.Vector + trackedClasses.put(java.util.Vector.class, + org.apache.jdo.impl.sco.Vector.class); + trackedClasses.put(org.apache.jdo.impl.sco.Vector.class, + org.apache.jdo.impl.sco.Vector.class); + + // java.util.SortedSet + trackedClasses.put(java.util.TreeSet.class, + org.apache.jdo.impl.sco.TreeSet.class); + trackedClasses.put(java.util.SortedSet.class, + org.apache.jdo.impl.sco.TreeSet.class); + trackedClasses.put(org.apache.jdo.impl.sco.TreeSet.class, + org.apache.jdo.impl.sco.TreeSet.class); + + // java.util.LinkedList + trackedClasses.put(java.util.LinkedList.class, + org.apache.jdo.impl.sco.LinkedList.class); + trackedClasses.put(java.util.AbstractSequentialList.class, + org.apache.jdo.impl.sco.LinkedList.class); + trackedClasses.put(org.apache.jdo.impl.sco.LinkedList.class, + org.apache.jdo.impl.sco.LinkedList.class); + + // java.util.Map + trackedClasses.put(java.util.Map.class, + org.apache.jdo.impl.sco.HashMap.class); + trackedClasses.put(java.util.AbstractMap.class, + org.apache.jdo.impl.sco.HashMap.class); + trackedClasses.put(java.util.HashMap.class, + org.apache.jdo.impl.sco.HashMap.class); + trackedClasses.put(org.apache.jdo.impl.sco.HashMap.class, + org.apache.jdo.impl.sco.HashMap.class); + + // java.util.Hashtable + trackedClasses.put(java.util.Hashtable.class, + org.apache.jdo.impl.sco.Hashtable.class); + trackedClasses.put(org.apache.jdo.impl.sco.Hashtable.class, + org.apache.jdo.impl.sco.Hashtable.class); + + // java.util.SortedMap + trackedClasses.put(java.util.SortedMap.class, + org.apache.jdo.impl.sco.TreeMap.class); + trackedClasses.put(java.util.TreeMap.class, + org.apache.jdo.impl.sco.TreeMap.class); + trackedClasses.put(org.apache.jdo.impl.sco.TreeMap.class, + org.apache.jdo.impl.sco.TreeMap.class); + } + } + + // + // Methods from PersistenceManagerFactory that are not already + // implemented in org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl. + // + + /** Create a new instance of PersistenceManager with + * the specific user name and password. + * @see org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl#createPersistenceManager(String userid, String password) + * @param userid the user name + * @param password the password + * @return the Persistencemanager + */ + protected PersistenceManager createPersistenceManager( + String userid, String password) { + + PersistenceManager rc = null; + try { + rc = new PersistenceManagerImpl(this, userid, password); + setConfigured(); + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "createPersistenceManager(userid, password)", ex); // NOI18N + } + return rc; + } + + /** Close this PersistenceManagerFactory. Check for + * JDOPermission("closePersistenceManagerFactory") and if not authorized, + * throw SecurityException. + *

If the authorization check succeeds, check to see that all + * PersistenceManager instances obtained from this PersistenceManagerFactory + * have no active transactions. If any PersistenceManager instances have + * an active transaction, throw a JDOUserException, with one nested + * JDOUserException for each PersistenceManager with an active Transaction. + *

If there are no active transactions, then close all PersistenceManager + * instances obtained from this PersistenceManagerFactory, mark this + * PersistenceManagerFactory as closed, disallow getPersistenceManager + * methods, and allow all other get methods. If a set method or + * getPersistenceManager method is called after close, then + * JDOUserException is thrown. + */ + public void close() { + super.close(); + /* remove this PMF from the map so another PMF with the same + * properties can be constructed. + */ + if (configuredFrom != null) { + synchronized (hashMapByFilteredProperties) { + hashMapByFilteredProperties.remove(configuredFrom); + } + } + close(true); + } + + /** + * Closes the database unless there are any active store managers. + * @param force If true, forces the database to close anyway, regardless of + * whether or not any store managers are still active. + * @return true if the database was closed, false if not (i.e., force is + * false and there are active store managers). + * @see javax.jdo.PersistenceManagerFactory#getPersistenceManager + */ + public boolean close(boolean force) { + boolean rc = false; + + try { + if (storeManagers.isEmpty() || force) { + if (logger.isDebugEnabled()) { + logger.debug("FOPMF closing database"); // NOI18N + } + if (null != cf) { + cf.closeDatabase(); + cf = null; + } + rc = true; + } + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "close", ex); // NOI18N + } + return rc; + } + + // + // Methods from PersistenceManagerFactoryInternal + // + + /** Override PersistenceManagerFactoryImpl's method so we can use our + * own cf variable. + * @param cf the connection factory + */ + public void setConnectionFactory(Object cf) { + this.cf = (FOStoreConnectionFactory) cf; + } + + /** + * Override PersistenceManagerFactoryImpl's method so that we can get a + * handle on the connection factory to close the database at close() time. + * @see org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl#getConnectionFactory + * @return the connection factory + */ + public synchronized Object getConnectionFactory () { + FOStoreConnectionFactory rc = cf; + + // If we already have a connection factory, use that. Otherwise, if + // our superclass has one, use that. Otherwise, make one, and use + // that. In the latter 2 cases, set our connection factory to be the + // one acquired/made. + if (null == rc) { + try { + cf = (FOStoreConnectionFactory)super.getConnectionFactory(); + if (logger.isDebugEnabled()) { + logger.debug("FOPMF.getCF: super.cf = " + cf); // NOI18N + } + if (null == cf) { + String cfName = getConnectionFactoryName(); + if (null != cfName) { + // cf = JNDI lookup of name + // XXX In what context? + } + } + if (null == cf) { + cf = new FOStoreConnectionFactory(); + cf.setPMF(this); + cf.setUserName(getConnectionUserName()); + cf.setPassword(password); + cf.setURL(getConnectionURL()); + cf.setCreate(create); + } + rc = cf; + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "getConnectionFactory", ex); // NOI18N + } + } + return rc; + } + + /** Verifies that the associated connection factory + * is configured (at least the URL is specified). + * @return if the connection factory is properly configured + */ + protected boolean isConnectionFactoryConfigured() { + return (cf==null?false:cf.isConfigured()); + } + + /** + * @see org.apache.jdo.pm.PersistenceManagerFactoryInternal#getTranscriberFactory() + * @return The PersistenceManagerFactory's transcriber factory. + */ + public TranscriberFactory getTranscriberFactory() { + return FOStoreTranscriberFactory.getInstance(); + } + + /** + * If parameter is non-null and implements PersistenceCapable, returns + * OID.class. + * @see org.apache.jdo.pm.PersistenceManagerFactoryInternal#getObjectIdClass( + * Class cls) + */ + public Class getObjectIdClass(Class cls) { + Class rc = null; + if (null != cls && PersistenceCapable.class.isAssignableFrom(cls)) { + JDOClass jdoClass = model.getJDOClass(cls); + rc = javaModelFactory.getJavaClass(jdoClass.getObjectIdClass()); + if (rc == null) + rc = OID.class; + } + return rc; + } + + /** + * @see org.apache.jdo.pm.PersistenceManagerFactoryInternal#getStoreManager( + * PersistenceManager pm) + */ + public StoreManager getStoreManager(PersistenceManager pm) { + FOStoreStoreManager rc = null; + try { + rc = (FOStoreStoreManager)storeManagers.get(pm); + if (null == rc) { + rc = new FOStoreStoreManager(this); + storeManagers.put(pm, rc); + } + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "getStoreManager", ex); // NOI18N + } + return rc; + } + + /** + * @see org.apache.jdo.pm.PersistenceManagerFactoryInternal#releaseStoreManager( + * PersistenceManager pm) + */ + public void releaseStoreManager(PersistenceManager pm) { + try { + storeManagers.remove(pm); + } catch (JDOException ex) { + throw ex; + } catch (Exception ex) { + throw new FOStoreFatalInternalException( + getClass(), "releaseStoreManager", ex); // NOI18N + } + } + + /** + * @see org.apache.jdo.pm.PersistenceManagerFactoryInternal#getTrackedClass( + * Class type) + */ + public Class getTrackedClass(Class type) { + initTrackedClasses(); + return (Class)trackedClasses.get(type); + } + + /** + * Returns metadata associated with this PersistenceManagerFactory. + */ + public FOStoreModel getModel() { + return model; + } + + // + // Package-private methods + // + + /** + * Provides the request factory. + * Currently, this is statically bound to return an instance of a + * {@link BufferedRequestFactory}. In the future, this could be + * configurable. + * @return A RequestFactory. + */ + RequestFactory getRequestFactory() { + return BufferedRequestFactory.getInstance(); + } + + /** + * Sets up a mapping from the given provisional OID to real OID. + * @exception JDOFatalException Thrown if the given OID is not provisional, or if + * the given provisional OID is already mapped to a real OID. + */ + // If you change this code, see method of same name in FOStoreDatabase. + void mapProvisionalOIDToReal(OID pOID, OID rOID) { + if (null == pOID || null == rOID || (! pOID.isProvisional())) { + throw new JDOFatalException(msg.msg("ERR_OIDNotProv", pOID)); // NOI18N + } + if (null != provisionalOIDs.get(pOID)) { + throw new JDOFatalException(msg.msg("ERR_DuplicateProvOID", pOID)); // NOI18N + } + provisionalOIDs.put(pOID, rOID); + } + + /** + * Provides the real OID for the given provisional OID. Returns null if + * there is no mapping. + * @exception JDOFatalException Thrown if the given OID is not provisional. + */ + // If you change this code, see method of same name in FOStoreDatabase. + OID getRealOIDFromProvisional(OID pOID) { + if (null == pOID || (! pOID.isProvisional())) { + throw new JDOFatalException(msg.msg("ERR_OIDNotProv", pOID)); // NOI18N + } + return (OID)provisionalOIDs.get(pOID); + } + + // + // Implement Externalizable + // Support for serialization. We don't have any state to save, but want + // all the superclass's state saved + // + + /** + * Writes this PMF's state to the given object output. + * @param out ObjectOutput to which this PMF's state is written. + */ + public void writeExternal(java.io.ObjectOutput out) + throws java.io.IOException { + + java.io.ObjectOutputStream oos = (java.io.ObjectOutputStream)out; + super.doWriteObject(oos); + oos.writeBoolean(create); + } + + /** + * Reads this PMF's state from the given object input. + * @param in ObjectInput from which this PMF's state is read. + */ + public void readExternal(java.io.ObjectInput in) + throws java.io.IOException, ClassNotFoundException { + + java.io.ObjectInputStream ois = (java.io.ObjectInputStream)in; + super.doReadObject(ois); + create = ois.readBoolean(); + } + + /** + * Uses rot13 algorithm. + * @see org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl#encrypt + */ + protected String encrypt(String s) { + return doEncrypt(s); + } + + /** + * Uses rot13 algorithm. + * @see org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl#decrypt + */ + protected String decrypt(String s) { + return doEncrypt(s); + } + + /** + * Use same encryption for others in this package (e.g. FOStoreConnectionFactory). + */ + static String doEncrypt(String s) { + return doDecrypt(s); + } + + /** + * Use same encryption for others in this package (e.g. FOStoreConnectionFactory). + */ + static String doDecrypt(String s) { + String rc = null; + if (null != s) { + rc = rot13(s); + } + return rc; + } + + // Standard Rot13 stuff. Translated to Java from a C implementation found + // on the net. + private static String rot13(String s) { + String rc = null; + int length = s.length(); + StringBuffer sb = new StringBuffer(length); + for (int i = 0; i < length; i++) { + int c = s.charAt(i); + int cap = c & 32; + c &= ~cap; + c = ((c >= 'A') && (c <= 'Z') ? ((c - 'A' + 13) % 26 + 'A') : c) | cap; + sb.append((char)c); + } + rc = sb.toString(); + if (logger.isDebugEnabled()) { + logger.debug("encrypted " + s + " to be " + rc); // NOI18N + } + return rc; + } + + /** + * @param create specifies whether to create the database */ + public void setConnectionCreate (boolean create) { + this.create = create; + } + + /** + * @param create tells whether to create the database*/ + public void setConnectionCreate (String create) { + this.create = Boolean.valueOf(create).booleanValue(); + } + + /** + * @return whether to create the database */ + public boolean getConnectionCreate() { + return create; + } + + /** + * @see org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl#setCFProperties + */ + protected void setCFProperties(Properties p) { + if (null != cf) { + cf.setProperties(p); + } + } + + /** + * @see org.apache.jdo.impl.pm.PersistenceManagerFactoryImpl#getCFFromProperties + */ + protected void getCFFromProperties(Properties p) { + cf = new FOStoreConnectionFactory(); + cf.setFromProperties(p); + } + + // + // Implement Referenceable + // + + /** + * Uses StringRefAddr's to store the information + */ + public Reference getReference() throws NamingException { + Reference rc = new Reference( + FOStorePMF.class.getName(), + FOStorePMFFactory.class.getName(), + null); + + Properties p = getAsProperties(); + for (Enumeration e = p.propertyNames(); e.hasMoreElements();) { + String key = (String)e.nextElement(); + String value = p.getProperty(key); + rc.add(new StringRefAddr(key, value)); + } + return rc; + } + + /** + * @return configuration information */ + public String toString() { + return super.toString() + + "model: " + model + "\n" + // NOI18N + "storeManagers: " + storeManagers + "\n" + // NOI18N + "provisionalOIDs: " + provisionalOIDs + "\n" + // NOI18N + "cf: " + cf + "\n"; // NOI18N + } + + /** + * @see PersistenceManagerFactoryImpl#getOptionArray + */ + protected String[] getOptionArray() { + return optionArray; + } + + /** A HashMap that associates PersistenceManagerFactory instances with a + * Properties instance. + */ + protected static HashMap hashMapByFilteredProperties = new HashMap(); + + /** + * Construct a Properties instance from the given Properties. Only + * those property entries recognized by this implementation will be + * stored in the internal Properties instance. + * + *

This method attempts to find an existing PersistenceManagerFactory + * with the properties as specified in the parameter. Only the non-default + * properties are considered when trying to find a match. + * + *

This method cannot be implemented by the superclass because + */ + public static PersistenceManagerFactoryImpl getPersistenceManagerFactory (Properties props) { + initPropsAccessors(); + FOStoreConnectionFactory.initPropsAccessors(); + Properties filtered = new Properties(); + filterProperties (props, filtered, pmfAccessors); + filterProperties (props, filtered, propsAccessors); + filterProperties (props, filtered, fostorePropsAccessors); + filterProperties (props, filtered, FOStoreConnectionFactory.CFpropsAccessors); + FOStorePMF pmf = null; + synchronized (hashMapByFilteredProperties) { + pmf = (FOStorePMF) hashMapByFilteredProperties.get (filtered); + if (pmf != null) return pmf; + pmf = new FOStorePMF(); + pmf.setFromProperties (filtered); + pmf.verifyConfiguration(); + pmf.setConfigured(); + hashMapByFilteredProperties.put (filtered, pmf); + pmf.configuredFrom = filtered; + } + return pmf; + } + + /** Set the PMF class property for this PMF. + */ + protected void setPMFClassProperty(Properties props) { + props.setProperty ("javax.jdo.PersistenceManagerFactoryClass", "org.apache.jdo.impl.fostore.FOStorePMF"); // NOI18N + } + + /** Method called by the shudown hook to close pmf instances left open + * when the JVM exits. + */ + protected void shutdown() { + super.shutdown(); + close(true); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMFFactory.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMFFactory.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMFFactory.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStorePMFFactory.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,65 @@ +/* + * 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.ByteArrayInputStream; +import java.io.IOException; +import java.io.ObjectInputStream; + +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Properties; + +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.Reference; +import javax.naming.spi.ObjectFactory; +import javax.naming.StringRefAddr; + +/** +* Creates a FOStorePMF when read in via JNDI. +*

+* This class is public so that JNDI can create instances. +* +* @author Dave Bristor +*/ +public class FOStorePMFFactory implements ObjectFactory { + + /** + * Uses StringRefAddr's to store the information + */ + public Object getObjectInstance( + Object obj, Name name, Context ctx, Hashtable env) throws Exception { + + FOStorePMF rc = null; + + if (obj instanceof Reference) { + Reference ref = (Reference)obj; + if (ref.getClassName().equals(FOStorePMF.class.getName())) { + Properties p = new Properties(); + for (Enumeration e = ref.getAll(); e.hasMoreElements();) { + StringRefAddr sra = (StringRefAddr)e.nextElement(); + p.setProperty(sra.getType(), (String)sra.getContent()); + } + + rc = new FOStorePMF(); + rc.setFromProperties(p); + } + } + return rc; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreRemoteConnection.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreRemoteConnection.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreRemoteConnection.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreRemoteConnection.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,136 @@ +/* + * 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. + */ + +/* + * FOStoreRemoteClientImpl.java + * + * Created on June 18, 2001, 4:44 PM + */ + +package org.apache.jdo.impl.fostore; + +import java.net.URL; +import java.net.Socket; + +import java.io.DataOutputStream; +import java.io.DataOutput; +import java.io.OutputStream; +import java.io.DataInput; +import java.io.DataInputStream; +import java.io.IOException; + +/** + * Represents a connection to a store that runs in a JVM separate from that of + * a client. + *

+ * This class is public so that clients can access the value of + * DEFAULT_PORT. + * + * @author Craig Russell + * @version 1.0 + */ +public class FOStoreRemoteConnection extends FOStoreClientConnectionImpl { + + /** The default port number + */ + public final static int DEFAULT_PORT = 9919; + + /** The socket used to communicate with the remote server. + */ + private Socket socket; + + /** The DataInputStream from the socket for replies from the server. + */ + private DataInput serverReplies; + + /** The DataOutputStream from the socket for requests for the server. + */ + private DataOutputStream clientRequests; + + /** Creates new FOStoreRemoteConnection + * @param url the url of the server. + */ + FOStoreRemoteConnection(URL url) { + super (url); + } + + /** Connect to the data store. The user name and password are stored in + * the connectionId. + * @throws IOException if a network error occurs + */ + public void connect() throws IOException { + String host = url.getHost(); + int port = url.getPort(); + if (port == -1) + port = DEFAULT_PORT; + if (logger.isDebugEnabled()) logger.debug("FOCCI:connect " + // NOI18N + " Host: " + host + // NOI18N + " Port: " + port); // NOI18N + socket = new Socket (host, port); + // we are connected; now send our greeting (login). + login(); + } + + /** + * Provides DataInput from which the client can read replies from + * the server. + * @return DataInput from which the client can read replies. + * @throws IOException if any problems. + */ + public DataInput getInputFromServer() throws IOException { + if (serverReplies == null) { + serverReplies = new DataInputStream (socket.getInputStream()); + } + return serverReplies; + } + + /** Write bytes to the store. This is the only method to actually write + * data bytes from the Message to the server. As soon as the remote side + * has read the bytes, it processes the message and sends the reply. + * @param buffer the data buffer + * @param offset the offset within the buffer + * @param length the number of bytes to write + * @throws IOException if any problems. + */ + public void sendToStore (byte[] buffer, int offset, int length) throws IOException { + if (clientRequests == null) { + OutputStream os = socket.getOutputStream(); + clientRequests = new DataOutputStream (os); + } + clientRequests.writeInt (length - offset); // receiver needs to allocate a buffer this big + clientRequests.write (buffer, offset, length); + } + + /** Close the database associated with this connection. This closes the socket + * associated, which causes the remote database to be closed. + * @throws IOException if any problems with the socket. + * @throws FOStoreDatabaseException if any problems with the database (not used here). + */ + public void closeDatabase() throws IOException, FOStoreDatabaseException { + socket.close(); + } + + /** + * @return The path as given, with the leading '/' removed if there is one. + */ + protected String localizePath(String path) { + // Use the correct path, not what Java gives you (see RFC1738) + if (path.startsWith("/")) { // NOI18N + path = path.substring(1); + } + return path; + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreSchemaUID.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreSchemaUID.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreSchemaUID.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreSchemaUID.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,238 @@ +/* + * 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.DataOutputStream; +import java.io.IOException; + +import java.security.MessageDigest; +import java.security.NoSuchAlgorithmException; +import java.security.DigestOutputStream; +import java.security.AccessController; +import java.security.PrivilegedAction; + +import java.util.HashMap; + +import javax.jdo.JDOFatalInternalException; +import javax.jdo.JDOUserException; +import javax.jdo.JDOFatalUserException; +import javax.jdo.spi.JDOImplHelper; +import javax.jdo.spi.PersistenceCapable; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.util.I18NHelper; + +/** +* A FOStoreSchemaUID is an internal name used to distinguish persistence +* capable classes based on the structure of their persistent fields as +* indicated by the enhancer. This is very similar to, and the implementation +* is based on, the process of computing a serialVersionUID as described in +* Object Serialization Specification, Section 4.4, Stream Unique Identifiers. // NOI18N +* +* @author Dave Bristor +*/ +class FOStoreSchemaUID { + /** The 'value' of this FOStoreSchemaUID */ + private final long fsuid; + + /** Map from ClassLoader to a HashMap that in turn maps from Class to + * FOStoreSchemaUID. + */ + private static final HashMap loaderMap = new HashMap(); + + /** 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 + + private static final FOStoreSchemaUID NOT_PERSISTENT = + new FOStoreSchemaUID(0); + + /** JDOImplHelper instance */ + private static final JDOImplHelper helper = + (JDOImplHelper) AccessController.doPrivileged ( + new PrivilegedAction () { + public Object run () { + try { + return JDOImplHelper.getInstance(); + } + catch (SecurityException e) { + throw new JDOFatalUserException (msg.msg( + e.getMessage()), e); // NOI18N + } + } + } + ); + + private FOStoreSchemaUID(long value) { + this.fsuid = value; + } + + private FOStoreSchemaUID(Class cls) { + this.fsuid = computeUID(cls); + } + + /** Provides a FOStoreSchemaUID corresponding to the given class. Any + * class which + *

+ * has a distinct FOStoreSchemaUID. All other classes share a common + * FOStoreSchemaUID. (A class can be PersistenceCapable but not enhanced + * by virtue of being in an inheritance chain, in which a class which does + * not have a JDO model inherits a class that does have a JDO model.) + * This should only be invoked by client code, never by server code, + * because it involves client-side concepts such as + * PersistenceCapable. + * @param cls Class for which a FOStoreSchemaUID is needed. + * @param model FOStoreModel for determining whether cls was enhanced. + * @return FOStoreSchemaUID corresponding to given Class. + */ + static synchronized FOStoreSchemaUID lookup(Class cls, FOStoreModel model) { + FOStoreSchemaUID rc = null; + if (! PersistenceCapable.class.isAssignableFrom(cls) || + model.getJDOClass(cls) == null) { + rc = NOT_PERSISTENT; + } else { + HashMap classMap = (HashMap)loaderMap.get(cls.getClassLoader()); + if (null == classMap) { + rc = new FOStoreSchemaUID(cls); + classMap = new HashMap(); + classMap.put(cls, rc); + loaderMap.put(cls.getClassLoader(), classMap); + } else { + rc = (FOStoreSchemaUID)classMap.get(cls); + if (null == rc) { + rc = new FOStoreSchemaUID(cls); + classMap.put(cls, rc); + } + } + } + return rc; + } + + private long computeUID(Class cls) { + long rc = 0; + try { + MessageDigest md = MessageDigest.getInstance("SHA"); // NOI18N + ByteArrayOutputStream baos = new ByteArrayOutputStream(512); + DigestOutputStream mdo = new DigestOutputStream(baos, md); + DataOutputStream data = new DataOutputStream(mdo); + + computeUID(cls, data); + + // Compute the hash value for cls + data.flush(); + byte hasharray[] = md.digest(); + for (int i = 0; i < Math.min(8, hasharray.length); i++) { + rc += (long)(hasharray[i] & 255) << (i * 8); + } + + } catch (IOException ex) { + // Can't happen, but be deterministic anyway + rc = -1; + } catch (NoSuchAlgorithmException ex) { + throw new JDOFatalInternalException( + msg.msg("ERR_Algorithm"), ex); // NOI18N + } + return rc; + } + + private void computeUID(Class cls, DataOutputStream out) + throws IOException { + + if (logger.isDebugEnabled()) { + logger.debug("FSUID.computeUID: " + cls.getName()); // NOI18N + } + + out.writeUTF(cls.getName()); + + // We don't need to sort these as the enhancer will have done that. + String names[] = helper.getFieldNames(cls); + Class types[] = helper.getFieldTypes(cls); + byte flags[] = helper.getFieldFlags(cls); + int length = names.length; + + for (int i = 0; i < length; i++) { + out.writeUTF(names[i]); + out.writeUTF(types[i].getName()); + out.writeByte(flags[i]); + } + + Class spr = helper.getPersistenceCapableSuperclass(cls); + if (null != spr) { + if (logger.isDebugEnabled()) { + logger.debug("FSUID: spr for " + cls.getName() + // NOI18N + " is " + cls.getName()); // NOI18N + } + computeUID(spr, out); + } + } + + public String toString() { + return "" + this.fsuid; // NOI18N + } + + // + // Support for I/O + // + + void write(DataOutput out) throws IOException { + out.writeLong(fsuid); + } + + static FOStoreSchemaUID read(DataInput in) throws IOException { + return new FOStoreSchemaUID(in.readLong()); + } + + // + // Support for equality + // + + public boolean equals(Object o) { + boolean rc = false; + if ((null != o) && (o instanceof FOStoreSchemaUID)) { + rc = (fsuid == ((FOStoreSchemaUID)o).fsuid); + } + return rc; + } + + /** + * Computes a hashcode for this FOStoreSchemaUID. The result is the + * exclusive OR of the two halves of the primitive long + * value represented by this Long object. That is, the + * hashcode is the value of the expression: + *
+     * (int)(this.longValue()^(this.longValue()>>>32))
+     * 
+ * This is the same algoritm as is used for java.lang.Long. + * + * @return a hash code value for this object. + */ + public int hashCode() { + // Same as for java.lang.Long + return (int)(fsuid ^ (fsuid >> 32)); + } +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnection.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnection.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnection.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnection.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,115 @@ +/* + * 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; + +/** +* A connection as used by a server/store. It provides a means of getting the +* client's input, and of writing reply data back to the client. +* +* @author Dave Bristor +*/ +interface FOStoreServerConnection extends FOStoreConnection { + /** + * Provides a DataInput from which the server can read the client's + * requests. + * @return DataInput for reading requests. + */ + public FOStoreInput getInputFromClient(); + + /** + * Provides a DataOutput to which the server can write data for the + * client. This is not normally used for writing data associated with a + * single reply (use createReply for that purpose). + * @return FOStoreOutput for writing data to client. + */ + public FOStoreOutput getOutputForClient(); + + /** + * Provides a Reply to which the server can write replies to the + * client's requests. + * @return Reply object for writing information about one reply. + */ + public Reply createReply(RequestId requestId) throws IOException; + + /** + * Adds the extent to this connections set of extents that have been + * changed during a transaction. + */ + public boolean addExtent(DBExtent dbExtent); + + /** + * Commits the work done in this connection. + */ + public void commit() throws FOStoreDatabaseException; + + /** + * Rolls back the work done in this connection. + */ + public void rollback() throws FOStoreDatabaseException; + + /** + * Sends all the reply data to the client. + */ + public void sendToClient() throws IOException, FOStoreDatabaseException; + + /** + * Provides the database to be used by the server using this connection. + * @return A database. + */ + public FOStoreDatabase getDatabase(); + + /** Set client data stream. Only used in local case. + */ + public void setClientInput (FOStoreInput in) throws IOException; + + /** Process requests from client. + */ + public void processRequests (); + + /** Log in to the database. + */ + public void openDatabase(String dbname, String user, long timestamp, byte[] secret, boolean create) + throws java.lang.InterruptedException, FOStoreDatabaseException; + + /** Provide the output from the server to the client reply handler. + */ + public DataInput getOutputFromServer(); + + /** Write the output from the server to the socket + */ + public void writeOutputToClient() throws IOException; + + /** Read the input stream from the socket. + */ + public void readInputFromClient() throws IOException; + + /** Close the database. Each open connection will perform this operation; + * only the last open connection to be closed will actually close the + * database. + */ + public void closeDatabase() throws FOStoreDatabaseException; + + /** Indicates whether or not it is OK to release a database after a + * message's contents are processed. + */ + // XXX TBD The server connection and implementation needs refactoring + public void setOkToReleaseDatabase(boolean ok); +} Added: incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnectionImpl.java URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnectionImpl.java?view=auto&rev=158176 ============================================================================== --- incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnectionImpl.java (added) +++ incubator/jdo/trunk/ri11/src/java/org/apache/jdo/impl/fostore/FOStoreServerConnectionImpl.java Fri Mar 18 17:02:29 2005 @@ -0,0 +1,355 @@ +/* + * 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. + */ + +/* + * FOStoreServerConnectionImpl.java + * + * Created on June 7, 2001, 3:16 PM + */ + +package org.apache.jdo.impl.fostore; + +import java.io.File; +import java.io.IOException; +import java.io.DataInput; +import java.io.ByteArrayInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.InputStream; +import java.io.OutputStream; + +import java.net.Socket; + +import java.util.HashSet; +import java.util.Iterator; + +import javax.jdo.JDOFatalInternalException; + +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; + +import org.apache.jdo.util.I18NHelper; + +/** + * + * @author Craig Russell + * @version 1.0 + */ + + /** This class implements the FOStoreServerConnection contract. It is used + * in two modes: local and remote. In local mode, the default constructor + * is used. In remote mode, the constructor that takes a Socket is used. + * The connection after construction does not contain any information about + * the data store. After the login request is successfully executed, the + * Database information is known. Subsequent requests know the Database. + */ +// XXX This class needs to be split into 2: one which handles the +// socket-connected case, the other which handles the local case. +class FOStoreServerConnectionImpl implements FOStoreServerConnection { + + /** 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 + + /** Used by server to write its replies. + */ + private FOStoreOutput serverData = new FOStoreOutput(); + + /** Used by server to read client's requests. + */ + private FOStoreInput clientDataInput; + + /** The socket over which we communicate to the client. + */ + private final Socket socket; + + /** Root in filesystem at which database will be created. + */ + private final String root; + + /** The input stream from the socket. Set after connect; reset at + * socket.close(). + */ + private DataInputStream socketDataInputStream = null; + + /** The output stream from the socket. Set after connect; reset at + * socket.close(). + */ + private OutputStream socketOutputStream = null; + + /** The local database name. + */ + private String dbname; + + /** The local database + */ + private FOStoreDatabase fodb; + + /** Indicates if releaseDatabase can really do so. + */ + private boolean okToReleaseDatabase = true; + + /** Creates new FOStoreServerConnectionImpl for the local case. + */ + public FOStoreServerConnectionImpl() { + this.socket = null; + this.root = null; + } + + /** Creates new FOStoreServerConnectionImpl for the remote case. + */ + public FOStoreServerConnectionImpl(Socket socket, String root) { + this.socket = socket; + this.root = root; + } + + /** + * Commits the work done in this connection. The database must already + * be connected. Stores in the database (a) the extents that have been + * changed and (b) the database's DBInfo. + */ + public void commit() throws FOStoreDatabaseException { + if (logger.isDebugEnabled()) logger.debug("FOSCI.commit"); // NOI18N + FOStoreDatabase db = getDatabase(); + + DBInfo dbInfo = db.getDBInfo(); + dbInfo.storeDirtyExtents(); + dbInfo.store(); + db.commitChanges(); + } + + /** + * Rolls back the work done in this connection. + */ + public void rollback() throws FOStoreDatabaseException { + FOStoreDatabase db = getDatabase(); + db.getDBInfo().clearDirtyExtents(); + db.rollbackChanges(); + } + + /** + * Provides a Reply to which the server can write replies to the + * client's requests. + * @return Reply object for writing information about one reply. + */ + public Reply createReply(RequestId requestId) throws IOException { + return new Reply(requestId, serverData); + } + + /** + * Provides a DataInput from which the server can read the client's + * requests. + * @return DataInput for reading requests. + */ + public FOStoreInput getInputFromClient() { + return clientDataInput; + } + + public void readInputFromClient() throws IOException { + if (socketDataInputStream == null) { + InputStream is = socket.getInputStream(); + socketDataInputStream = new DataInputStream (is); + } + if (logger.isDebugEnabled()) { + logger.debug ( + "FOSCI.readInputFromClient available: " + // NOI18N + socketDataInputStream.available()); + } + + int length = socketDataInputStream.readInt(); + byte[] buffer = new byte[length]; + socketDataInputStream.readFully(buffer); + setClientInput( new FOStoreInput (buffer, 0, length)); + } + + /** + * @see FOStoreServerConnection#sendToClient + */ + public void sendToClient() throws IOException, FOStoreDatabaseException { + } + + /** + * Adds the extent to this connections set of extents that have been + * changed during a transaction. They will be put to the database when + * sendToClient is invoked. + */ + public boolean addExtent(DBExtent dbExtent) { + boolean rc = getDatabase().getDBInfo().makeExtentDirty(dbExtent); + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.addExtent to: " + this + // NOI18N + " dbExtent: " + dbExtent + // NOI18N + "add rc: " + rc); // NOI18N + } + return rc; + } + + /** Open the database if it exists, and verify the user authentication. + * If the database does not exist, create it. + */ + public void openDatabase (String dbname, String user, long timestamp, + byte[] secret, boolean create) + throws FOStoreDatabaseException, InterruptedException { + + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.openDatabase " + dbname + // NOI18N + " user: " + user); // NOI18N + } + + fodb = FOStoreDatabase.getDatabase(databasePath(dbname), create); + this.dbname = dbname; + fodb.verifyUserPassword(user, timestamp, secret); + } + + /** + * Provides the database to be used by the server using this connection. + * @return A database. + */ + public FOStoreDatabase getDatabase() { + try { + if (fodb == null) { + fodb = FOStoreDatabase.getDatabase( + databasePath(dbname), false); + } + return fodb; + } catch (InterruptedException ex) { + throw new JDOFatalInternalException( + msg.msg("ERR_GetDatabaseInterrupted"), ex); // NOI18N + } catch (FOStoreDatabaseException ex) { + throw new JDOFatalInternalException( + msg.msg("ERR_GetDatabaseException"), ex); // NOI18N + } + } + + /** + * Provides a DataOutput to which the server can write data for the + * client. This is not normally used for writing data associated with a + * single reply (use createReply for that purpose). + * @return FOStoreOutput for writing data to client. + */ + public FOStoreOutput getOutputForClient() { + return serverData; + } + + /** Provides a DataInput from which the local client can read the server's + * replies. Reset for the next output request. + */ + public DataInput getOutputFromServer() { + DataInput di = new DataInputStream( + new ByteArrayInputStream( + serverData.getBuf(), 0, serverData.getPos())); + + serverData.reset(); // reset the output stream + return di; + } + + /** Writes the output to the client socket. Reset for the next output + * request. + */ + public void writeOutputToClient() throws IOException { + if (socketOutputStream == null) { + if (logger.isDebugEnabled()) { + logger.debug( + "FOSCI.writeOutputToClient getting socketOutputStream"); // NOI18N + } + + socketOutputStream = socket.getOutputStream(); + if (logger.isDebugEnabled()) { + logger.debug( + "FOSCI.writeOutputToClient got socketOutputStream"); // NOI18N + } + } + + if (logger.isDebugEnabled()) { + logger.debug( + "FOSCI.writeOutputToClient writing socketOutputStream: " + // NOI18N + serverData.getPos() + " bytes"); // NOI18N + } + + socketOutputStream.write(serverData.getBuf(), 0, serverData.getPos()); + serverData.reset(); // reset the output stream + } + + public void setClientInput (FOStoreInput fi) { + clientDataInput = fi; + } + + public void processRequests() { + RequestHandler.handleRequests(this); + } + + /** Indicates whether or not releaseDatabase can actually release the + * database. + */ + public void setOkToReleaseDatabase(boolean ok) { + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.setOk: " + ok); // NOI18N + } + this.okToReleaseDatabase = ok; + } + + /** Release the database associated with this connection. + */ + void releaseDatabase() throws InterruptedException { + if (okToReleaseDatabase && fodb != null) { + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.releaseDatabase: releasing"); // NOI18N + } + FOStoreDatabase.releaseDatabase(fodb); + fodb = null; + } + } + + /** Close the database associated with this connection. + */ + public void closeDatabase() throws FOStoreDatabaseException { + try { + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.closeDatabase " + dbname); // NOI18N + } + releaseDatabase(); + FOStoreDatabase.closeDatabase(databasePath(dbname)); + } catch (InterruptedException ex) { + throw new JDOFatalInternalException( + msg.msg("ERR_CloseDatabaseInterrupted"), ex); // NOI18N + } + } + + /** Close this connection; release all resources. + */ + public void close() throws FOStoreDatabaseException { + if (logger.isDebugEnabled()) { + logger.debug("FOSCI.close " + dbname); // NOI18N + } + closeDatabase(); + } + + /** @return A String for the databse's pathnamne. It is based on the + * given dbname, plus the root, if one was given when this connection was + * created. + */ + private final String databasePath(String dbname) { + String rc; + if (null == root) { + rc = dbname; + } else { + rc = root + File.separator + dbname; + } + return rc; + } +}