You are viewing a plain text version of this content. The canonical link for it is here.
Posted to jdo-commits@db.apache.org by mb...@apache.org on 2005/05/22 20:40:21 UTC
svn commit: r171355 [11/31] - in /incubator/jdo/trunk/fostore20: ./ src/
src/conf/ src/java/ src/java/org/ src/java/org/apache/
src/java/org/apache/jdo/ src/java/org/apache/jdo/impl/
src/java/org/apache/jdo/impl/fostore/ test/ test/conf/ test/fsuid2/
test/fsuid2/org/ test/fsuid2/org/apache/ test/fsuid2/org/apache/jdo/
test/fsuid2/org/apache/jdo/pc/ test/java/ test/java/org/
test/java/org/apache/ test/java/org/apache/jdo/
test/java/org/apache/jdo/impl/ test/java/org/apache/jdo/impl/fostore/
test/java/org/apache/jdo/pc/ test/java/org/apache/jdo/pc/appid/
test/java/org/apache/jdo/pc/empdept/
test/java/org/apache/jdo/pc/serializable/
test/java/org/apache/jdo/pc/xempdept/ test/java/org/apache/jdo/test/
test/java/org/apache/jdo/test/query/ test/java/org/apache/jdo/test/util/
test/jdo/ test/jdo/org/ test/jdo/org/apache/ test/jdo/org/apache/jdo/
test/jdo/org/apache/jdo/pc/ test/jdo/org/apache/jdo/pc/appid/
test/jdo/org/apache/jdo/pc/empdept/ test/jdo/org/apache/jdo/pc/serializable/
test/jdo/org/apache/jdo/pc/xempdept/
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ReplyHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ReplyHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ReplyHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ReplyHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,249 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.jdo.JDODataStoreException;
+import javax.jdo.JDOFatalDataStoreException;
+import javax.jdo.JDOFatalUserException;
+import javax.jdo.JDOOptimisticVerificationException;
+import javax.jdo.JDOUserException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.store.Connector;
+import org.apache.jdo.util.I18NHelper;
+
+/**
+* Processes replies that are received from the store. Dispatches each one to
+* its corresponding Request.
+* @author Dave Bristor
+*/
+
+// Perhaps this class isn't necessary, and it's functionality should be
+// moved into AbstractRequest. In any case, either it should be called
+// ReplyProcessor or the single method should be named handleReplies.
+
+// This is client-side code. It does not need to live in the server.
+abstract class ReplyHandler {
+ /** 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
+
+ /**
+ * Process all replies in the given input stream. The format of the
+ * DataInput is<br>
+ * <pre>
+ * Version number of the Reply data (of the whole enchilada, not of the
+ * individual Reply instances).
+ * Status value indicating the overall success by the server in processing
+ * the Message.
+ * </pre>
+ * The expected Status value is either OK or FATAL. If FATAL, then the
+ * next item is
+ * <pre>
+ * String: message from server (such as exception string or stack trace).
+ * </pre>
+ * Otherwise, the next item is
+ * <pre>
+ * int: number of replies
+ * </pre>
+ * In the FATAL case, all other data is ignored. Otherwise the remaining
+ * data is, per reply:
+ * <pre>
+ * RequestId: of the request corresponding to the reply data being read
+ * Status: of the individual reply
+ * MessagePos: int which indicates where in the DataInput is a String that
+ * was generated by the processing of the reply's request. If this is 0,
+ * then there is no message.
+ * length: int indicating the length of the reply's data.
+ * request-specific data: length bytes of data associated with the reply.
+ * </pre>
+ */
+ static void processReplies(DataInput in, Message message) {
+ ArrayList exceptions = new ArrayList();
+ boolean optimistic_failure = false;
+
+ try {
+ try {
+ Reply.verifyVersionNumber(in);
+ } catch (JDOFatalUserException ex) {
+ throw ex;
+ }
+
+ // Overall status of a reply is FATAL, ROLLBACK, LOGIN, or OK.
+ Status replyStatus = new Status(in);
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "ReplyHandler.hR: replyStatus=" + replyStatus); // NOI18N
+ }
+ if (replyStatus.equals(Status.FATAL)) {
+ // Don't process any replies, just throw a
+ // JDOFatalDataStoreException so that upper levels can
+ // rollback, etc. as necessary.
+ Connector c = message.getConnector();
+ if (null != c) {
+ c.setRollbackOnly();
+ }
+ String str = in.readUTF();
+ // sic: DataStoreException. This was decided upon after much
+ // email discussion.
+ throw new JDODataStoreException(
+ msg.msg("ERR_FatalReply", str)); // NOI18N
+
+ } else if (replyStatus.equals(Status.LOGIN)) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("ReplyHandler: Login failure"); // NOI18N
+ }
+ String str = in.readUTF();
+ throw new JDOFatalDataStoreException(str);
+
+ } else if (replyStatus.equals(Status.ROLLBACK)) {
+ // The rollback was at user request. Don't process any
+ // replies, but don't throw any exception either.
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "ReplyHandler.processReplies: ROLLBACK"); // NOI18N
+ }
+ int skipLength = in.readInt();
+ in.skipBytes(skipLength);
+ } else {
+ // Process each reply.
+ int numReplies = in.readInt();
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "ReplyHandler.processReplies: numReplies=" + // NOI18N
+ numReplies);
+ }
+
+ for (int i = 0; i < numReplies; i++) {
+ RequestId requestId = new RequestId(in);
+ Status status = new Status(in);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "ReplyHandler: " + requestId + // NOI18N
+ ", " + status); // NOI18N
+ }
+
+ int messagePos = in.readInt();
+ Request request = message.getRequest(requestId);
+ if (null == request) {
+ // This could happen if a "nested" request is being
+ // processed, i.e. this requestId was already removed
+ // from the list but was not finished processing.
+ int length = in.readInt();
+ in.skipBytes(length);
+ continue;
+ /*
+ throw new FOStoreFatalInternalException(
+ ReplyHandler.class, "processReplies", // NOI18N
+ msg.msg(
+ "ERR_CannotGetRequest", requestId)); // NOI18N
+ */
+ }
+ int length = in.readInt();
+
+ if (0 != messagePos) {
+ if (status.equals(Status.OK) ||
+ status.equals(Status.WARN)) {
+
+ // If there's a message with non-erroneus status,
+ // let request handle reply. Note: Request
+ // *MUST* read message in this case!
+ request.handleReply(status, in, length);
+
+
+ // The next 2 cases are similar, differing only
+ // in whether the user could retry the operation
+ // or not. In both cases, skip the reply data
+ // (it might not even be valid, though it's
+ // length is) and add the message in an
+ // exception.
+ } else if (status.equals(Status.FATAL)) {
+ in.skipBytes(length);
+ String str = in.readUTF();
+ throw new JDOFatalDataStoreException(str);
+ } else if (status.equals(Status.OPTIMISTIC)) {
+ // overall status is failed due to optimistic verification
+ optimistic_failure = true;
+ // when the result is Status.OPTIMISTIC, the result
+ // contains the oid of the failed operation
+ OID oid = OID.read(in);
+ StateManagerInternal sm = request.getStateManager();
+ Object failed = (sm == null) ? null : sm.getObject();
+ String str = in.readUTF();
+ exceptions.add(new JDOOptimisticVerificationException(str, failed));
+ } else {
+ in.skipBytes(length);
+ String str = in.readUTF();
+ exceptions.add(new JDODataStoreException(str));
+ }
+ } else if (status.equals(Status.ERROR) ||
+ status.equals(Status.FATAL)) {
+ // If there's no message but the status reports an
+ // error then we have a bug.
+ throw new JDOFatalDataStoreException();
+ } else {
+ // No message, non-ERROR status: let request handle
+ // reply
+ request.handleReply(status, in, length);
+ }
+ }
+ }
+ } catch (IOException ex) {
+ throw new FOStoreFatalIOException(
+ ReplyHandler.class, "processReplies", ex); // NOI18N
+ }
+
+ int numExceptions = exceptions.size();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "ReplyHandler.processReplies: finished; " + // NOI18N
+ "numExceptions=" + numExceptions); // NOI18N
+ }
+
+ if (numExceptions > 0) {
+ // We can't use exceptions.toArray() because you wouldn't have
+ // the debugging output.
+ // XXX use toArray(Throwable[])
+ Throwable t[] = new Throwable[numExceptions];
+ for (int i = 0; i < numExceptions; i++) {
+ t[i] = (Throwable)exceptions.get(i);
+ if (logger.isDebugEnabled()) {
+ logger.debug("RH.rH: " + t[i]); // NOI18N
+ }
+ }
+ if (optimistic_failure) {
+ throw new JDOOptimisticVerificationException(
+ msg.msg("EXC_Optimistic"), t); // NOI18N
+ } else {
+ throw new JDODataStoreException(
+ msg.msg("EXC_Exceptions"), t); // NOI18N
+ }
+ }
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Request.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Request.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Request.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Request.java Sun May 22 11:40:13 2005
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.IOException;
+
+import org.apache.jdo.state.StateManagerInternal;
+
+
+/**
+ * Represents the ability to send information to the actual file/object store.
+ *
+ * @author Dave Bristor
+ */
+interface Request {
+ /** Does whatever it is that the kind of request does in actually making a
+ * request of the store.
+ * @throws IOException in case of errors with the stream.
+ */
+ public void doRequest() throws IOException;
+
+ /** Processes the results of the effect of the request in the store. To be
+ * invoked after the store has processed the request, and has returned
+ * information about that request, such as its status and any accompanying
+ * data.
+ * @param in the input stream.
+ * @param length the length of data in the stream.
+ * @param status Indication as to the success, failure, etc. of the
+ * request as handled by the store.
+ * @throws IOException if any problems reading the stream.
+ */
+ public void handleReply(Status status, DataInput in, int length)
+ throws IOException;
+
+ /** Get the StateManager associated with this request, null if none.
+ * @return the StateManager.
+ */
+ public StateManagerInternal getStateManager();
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFactory.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFactory.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFactory.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFactory.java Sun May 22 11:40:13 2005
@@ -0,0 +1,195 @@
+/*
+ * 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 org.apache.jdo.pm.PersistenceManagerInternal;
+import org.apache.jdo.state.StateManagerInternal;
+
+
+/**
+ * Creates different kinds of requests.
+ *
+ * @author Dave Bristor
+ */
+interface RequestFactory {
+ /**
+ * Creates a request object that will get a datastore OID for a
+ * provisional OID.
+ */
+ public CreateOIDRequest getCreateOIDRequest(
+ StateManagerInternal sm, Message m, FOStorePMF pmf,
+ OID oid, PersistenceManagerInternal pm);
+
+ /**
+ * Creates a request object to activate the class corresponding to the
+ * given oid.
+ * @param cls Class to be activated.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public ActivateClassRequest getActivateClassRequest(
+ Class cls, Message m, FOStorePMF pmf);
+
+ /**
+ * Creates a request object to cause a persistent object to be inserted
+ * into the datastore.
+ * @param sm StateManagerInternal of the object to be stored in the
+ * datastore.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public InsertRequest getInsertRequest(
+ StateManagerInternal sm, Message m, FOStorePMF pmf);
+
+ /**
+ * Creates a request object to cause one or more fields of a persistent
+ * object to be updated in the store.
+ * @param sm StateManagerInternal of the object to be updated.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ * @param loadedFields Set of fields loaded from the database.
+ * @param dirtyFields Set of fields that are to be flushed and
+ * verified against the those in the database, if this
+ * <code>update</code> is within the context of an optimistic
+ * transaction.
+ * @param optimistic If true, then update is happening in context of
+ * optimistic transaction, otherwise datastore transaction.
+ */
+ public UpdateRequest getUpdateRequest(
+ StateManagerInternal sm, Message m, FOStorePMF pmf,
+ BitSet loadedFields, BitSet dirtyFields, boolean optimistic);
+
+ /**
+ * Creates a request object to verify that in-memory data is the same as
+ * that in the database.
+ * @param sm StateManagerInternal of the object to be verified.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ * @param verifyFields If true, verify values of object, otherwise verify
+ * only existence (and ignore remaining parameters).
+ * @param loadedFields Set of fields to be verified against those in the
+ * database.
+ */
+ public VerifyRequest getVerifyRequest(
+ StateManagerInternal sm, Message m, FOStorePMF pmf,
+ boolean verifyFields, BitSet loadedFields);
+
+ /**
+ * Creates a request object to cause one or more fields of a persistent
+ * object to be read from the store.
+ * @param sm StateManagerInternal of the object whose field(s) are to be
+ * read.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public FetchRequest getFetchRequest(
+ StateManagerInternal sm, Message m, FOStorePMF pmf);
+
+ /**
+ * Creates a request object to cause a particular class's extent to be
+ * retrieved.
+ * @param extent FOStoreExtent for which the request is being created.
+ * @param pcClass Class of the objects whose extent is sought. It is
+ * <em>required</em> that the caller ensure that the given pcClass
+ * implement javax.jdo.PersistenceCapable.
+ * @param subclasses If false, retrieve instances of pcClass only; if true
+ * retrieve those plus all instances of subclasses of pcClass.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pm PersistenceManager on whose behalf the request is taking
+ * place.
+ */
+ public GetExtentRequest getGetExtentRequest(
+ FOStoreExtent extent, Class pcClass,
+ boolean subclasses, Message m,
+ PersistenceManagerInternal pm);
+
+ /**
+ * Creates a request to get instances for some oids.
+ * @param oids List of oids for which instances are needed.
+ * @param start Starting index in oids for which instances are needed.
+ * @param numInstances Number of instances which are needed.
+ * @param pm PersistenceManager on whose behalf the request is taking
+ * place.
+ * @param cls Candidate Class for which instances are being obtained.
+ */
+ public GetInstancesRequest getGetInstancesRequest(
+ ArrayList oids, int start, int numInstances,
+ Message m, PersistenceManagerInternal pm, Class cls);
+
+ /**
+ * Creates a request object to cause a persistent object in the store to
+ * be deleted.
+ * @param sm StateManagerInternal of the object to delete in the store.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public DeleteRequest getDeleteRequest(
+ StateManagerInternal sm, Message m, FOStorePMF pmf);
+
+ /**
+ * Creates a request object to cause the java.lang.Class associated with
+ * the given CLID to be provided.
+ * @param clid CLID of the class that is needed.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ * @param pm PersistenceManager used to load the class.
+ * place.
+ */
+ public GetClassRequest getGetClassRequest(
+ CLID clid, Message m, FOStorePMF pmf, PersistenceManagerInternal pm);
+
+ /**
+ * Creates a request object which notifies the store of the kind of
+ * transaction that is starting.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ * @param optimistic Indicates whether an optimistic or datastore
+ * transaction is beginning.
+ */
+ public BeginTxRequest getBeginTxRequest(
+ Message m, FOStorePMF pmf, boolean optimistic);
+
+ /**
+ * Creates a request object which causes previous operations to commit.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public CommitRequest getCommitRequest(
+ Message m, FOStorePMF pmf);
+
+ /**
+ * Creates a request object which causes previous operations to rollback.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public RollbackRequest getRollbackRequest(
+ Message m, FOStorePMF pmf);
+
+ /**
+ * Creates a request object to get information from the store.
+ * @param option Diagnostic parameter code.
+ * @param className Optional class name.
+ * @param m Message by which the request is to be sent to the store.
+ * @param pmf FOStorePMF in which the request is taking place.
+ */
+ public DumpRequest getDumpRequest(
+ DumpOption option, String className, Message m,
+ FOStorePMF pmf);
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFinisher.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFinisher.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFinisher.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestFinisher.java Sun May 22 11:40:13 2005
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+/**
+ * Means by which a request can indicate that there is work to be done
+ * once all requests have been processed.
+ *
+ * @author Dave Bristor
+ */
+interface RequestFinisher {
+ /**
+ * Does some post-request processing work on behalf of the request which
+ * created it.
+ */
+ public void finish();
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,391 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.ArrayList;
+
+import javax.jdo.JDOException;
+import javax.jdo.JDOFatalDataStoreException;
+import javax.jdo.JDOFatalUserException;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import org.apache.jdo.util.I18NHelper;
+
+/**
+* This dispatches each request received by the store to the appropriate
+* request-type-specific request handler. It is very dependent on the
+* 'message full of data' means of communicating between client and store.
+*
+* @author Dave Bristor
+*/
+//
+// This is server-side code. It does not need to live in the client.
+//
+abstract class RequestHandler {
+ /** Subclasses use this Reply instance to send data back to their
+ * corresponding client-side request. */
+ protected final Reply reply;
+
+ /** Length of the data in the Request. */
+ protected final int length;
+
+ /** Connection on which the Request arrived. */
+ protected final FOStoreServerConnection con;
+
+ /** 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
+
+ /** Means by which subclasses are created. Each RequestHandler subclass
+ * should have a static inner class that implements this interface.
+ */
+ interface HandlerFactory {
+ /**
+ * @param reply Reply instance into which the returned handler may
+ * write request/reply - specific information.
+ * @param length Length in bytes of the request data.
+ * @param con Connection from which the request was made.
+ *@return A RequestHandler instance for a specific subclass of
+ * RequestHandler.
+ */
+ public RequestHandler getHandler(Reply reply, int length,
+ FOStoreServerConnection con);
+ }
+
+ /**
+ * @param reply Reply to which request handler should write all reply
+ * information.
+ * @param length Number of bytes in the connection's input that are for
+ * this request; subclasses <strong>must</strong> read all bytes so that
+ * other requests can work.
+ * @param con Connection from which request handler reads the
+ * request data.
+ */
+ protected RequestHandler(Reply reply, int length,
+ FOStoreServerConnection con) {
+
+ this.reply = reply;
+ this.length = length;
+ this.con = con;
+ }
+
+ /**
+ * The RollbackHandler should override this and return false, so that
+ * finishers are not run when we are rolling back.
+ */
+ protected boolean getOkToFinish() {
+ return true;
+ }
+
+ /**
+ * The CommitHandler should override this and save the given value, then
+ * use it to determine whether or not to commit.
+ */
+ protected void setOkToCommit(boolean okToCommit) { }
+
+ /**
+ * Handles all requests that can be read at this time from the given
+ * connection. Reads the number of requests, then reads each one and, in
+ * turn, invokes the handleRequest operation on each.
+ * <p>
+ * The data it generates for the client is documented; see {@link
+ * ReplyHandler#processReplies}.
+ * <p>
+ * If after all requests are thusly handled, none have indicated that the
+ * second round of handling, called finishing, is not to be done, then
+ * performs this second round. The finishers that are invoked are
+ * precisely those which were returned from each request's handleRequest
+ * invocation, and the finishers have their finish() methods invoked in
+ * the same order in which the requests were originally invoked.
+ * <p>
+ * Finally, writes the number of replies (at the beginning of the reply
+ * data, in a spot that was set aside for this purpose), and sends replies
+ * back to the client.
+ * <p>
+ * This method is <em>very</em> paranoid about error checking, which
+ * clutters it up some, but is necessary to ensure that the server keeps
+ * running.
+ */
+ static void handleRequests(FOStoreServerConnection con) {
+ // List of finishers to run after all requests have been handled.
+ // Provides a means for a second phase of operations to run, at the
+ // request of the requests themselves. Re-initialized each time
+ // handleRequests is run.
+ // @see Message#sendToStore for stream header writer.
+ ArrayList finishers = new ArrayList();
+
+ DataInput in = con.getInputFromClient();
+ int numRequests = 0;
+
+ FOStoreOutput serverData = con.getOutputForClient();
+ int numReplies = 0;
+
+ // Result of processing all requests. Written as part of the reply
+ // data's "header".
+ Status overallStatus = Status.OK;
+
+ // Position in serverData where the reply's overall status is written.
+ // Used in case we have to overwrite that value.
+ //
+ // Why do we initialize statusPos?
+ // We have to because if not, the compiler complains that it might
+ // not have been initialized, at it is used as an R-value. And while
+ // this is technically true, in fact it is initialized right away
+ // inside the first try block, and nothing at or before that
+ // initialization can throw an exception. (Well, at least not
+ // anything we'd ever recover from.)
+ int statusPos = 0;
+
+ // Position in serverData wher number of replies is written.
+ int numRepliesPos;
+
+ // If true, then run finishers after handling all requests.
+ // This is set below by invoking okToFinish on each RequestHandler
+ // instance. Only RollbackHandler should return false.
+ boolean okToFinish = true;
+
+ // The message might contain a CommitRequest. We assume that all
+ // requests will succeed. But if one of them sets its reply's status
+ // to Status.ERROR or Status.FATAL, we don't commit.
+ boolean okToCommit = true;
+
+ try {
+ Reply.writeVersionNumber(serverData);
+
+ // Write a default overall status of the reply. Will be
+ // overwritten later if there are any fatal problems in processing
+ // the requests.
+ statusPos = serverData.getPos();
+ overallStatus.write(serverData);
+
+ // Write a default number of replies. Later write the real number
+ // of replies.
+ numRepliesPos = serverData.getPos();
+ serverData.writeInt(0);
+
+ try {
+ Message.verifyVersionNumber(in);
+ numRequests = in.readInt();
+ if (logger.isDebugEnabled()) {
+ logger.debug("RequestHandler: numRequests=" + // NOI18N
+ numRequests);
+ }
+ } catch (JDOFatalUserException ex) {
+ // Message version mismatch
+ throw ex;
+ } catch (IOException ex) {
+ throw new FOStoreFatalIOException(
+ RequestHandler.class,
+ "handleRequests/numRequests ", ex); // NOI18N
+ }
+
+ for (int i = 0; i < numRequests; i++) {
+ Reply reply = null; // Prepare for this iteration.
+ RequestId requestId = new RequestId(in);
+ RequestType requestType = new RequestType(in);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("RequestHandler: " + // NOI18N
+ requestId + "/" + // NOI18N
+ requestType);
+ }
+
+ HandlerFactory factory = requestType.getHandlerFactory();
+ if (null == factory) {
+ throw new FOStoreFatalInternalException(
+ RequestHandler.class, "handleRequests", // NOI18N
+ msg.msg("ERR_CannotCreateHandler", // NOI18N
+ requestType.toString()));
+ }
+ int length = in.readInt();
+ reply = con.createReply(requestId);
+ numReplies++;
+
+ RequestHandler rh =
+ factory.getHandler(reply, length, con);
+
+ // Run the request, and save it's finisher (if any)
+ rh.setOkToCommit(okToCommit);
+ RequestFinisher rf = rh.handleRequest();
+
+ // Check for commit- and finish- ability
+ Status replyStatus = reply.getStatus();
+ if (Status.ERROR.equals(replyStatus) ||
+ Status.FATAL.equals(replyStatus) ||
+ Status.OPTIMISTIC.equals(replyStatus)) {
+
+ okToCommit = false;
+
+ } else if (Status.ROLLBACK.equals(replyStatus)) {
+ okToCommit = false;
+
+ // No point in doing work that'll just be undone
+ okToFinish = false;
+
+ // Mark the status as rolled back.
+ overallStatus = replyStatus;
+ int pos = serverData.getPos();
+ serverData.setPos(statusPos);
+ overallStatus.write(serverData);
+
+ // Instead of number of replies, write the number of bytes
+ // in the reply, so that the client can skip them.
+ serverData.setPos(numRepliesPos);
+ serverData.writeInt(pos - numRepliesPos);
+
+ serverData.setPos(pos);
+
+ // Once a rollback has been requested, there's no point in
+ // processing other replies.
+ break;
+
+ } else {
+ okToFinish = rh.getOkToFinish();
+ if (okToFinish && null != rf) {
+ finishers.add(rf);
+ }
+ }
+ }
+
+ if (okToFinish) {
+ // Run the finishers they produced (if any).
+ int numFinishers = finishers.size();
+ for (int i = 0; i < numFinishers; i++) {
+ RequestFinisher rf = (RequestFinisher)finishers.get(i);
+ if (logger.isDebugEnabled()) {
+ logger.debug(
+ "RequestHandler.hR: finish " + // NOI18N
+ rf.getClass().getName());
+ }
+ rf.finish();
+ }
+ }
+
+ // If rollback, numRepliesPos already overwritten with length of
+ // reply data.
+ if (! overallStatus.equals(Status.ROLLBACK)) {
+ // Write the number of replies produced.
+ int pos = serverData.getPos();
+ serverData.setPos(numRepliesPos);
+ serverData.writeInt(numReplies);
+ serverData.setPos(pos);
+ }
+
+ } catch (FOStoreLoginException ex) {
+ if (logger.isDebugEnabled()) {
+ logger.debug("Login failure"); // NOI18N
+ }
+ try {
+ int pos = serverData.getPos();
+ serverData.setPos(statusPos);
+ overallStatus = Status.LOGIN;
+ overallStatus.write(serverData);
+ serverData.writeUTF(ex.toString());
+ int messagePos = serverData.getPos();
+ if (messagePos > pos) {
+ pos = messagePos;
+ }
+ serverData.setPos(pos);
+ } catch (IOException ex2) {
+ giveUp(ex2);
+ }
+
+ } catch (Throwable ex) {
+ // Handle unexpected failure. Inform client that the replies
+ // could not be processed. Rollback the database.
+ if (logger.isDebugEnabled()) {
+ ex.printStackTrace();
+ }
+ try {
+ int pos = serverData.getPos();
+ serverData.setPos(statusPos);
+ overallStatus = Status.FATAL;
+ overallStatus.write(serverData);
+ String message = Reply.getExceptionMessage(ex);
+ if (null == message) {
+ message = msg.msg("EXC_Unknown"); // NOI18N
+ }
+ serverData.writeUTF(message);
+ int messagePos = serverData.getPos();
+ if (messagePos > pos) {
+ pos = messagePos;
+ }
+ serverData.setPos(pos);
+
+ try {
+ con.rollback();
+ } catch (FOStoreDatabaseException ex2) {
+ // Oh well, we tried.
+ }
+ } catch (IOException ex2) {
+ giveUp(ex2);
+ }
+
+ } finally {
+ try {
+ con.sendToClient();
+
+ if (logger.isDebugEnabled()) {
+ if (Status.OK == overallStatus) {
+ logger.debug(
+ "RequestHandler: " + overallStatus + // NOI18N
+ ", numReplies=" + numReplies); // NOI18N
+
+ } else {
+ logger.debug(
+ "RequestHandler: " + overallStatus); // NOI18N
+ }
+ }
+ } catch (IOException ex) {
+ giveUp(ex);
+ } catch (FOStoreDatabaseException ex) {
+ giveUp(ex);
+ }
+ }
+ }
+
+ /**
+ * Invoke this when all attempts at communicating errors to the client
+ * have failed. Hope that someone is watching the console!
+ */
+ private static void giveUp(Throwable ex) {
+ System.err.println(msg.msg("ERR_SendToClient", ex)); // NOI18N
+ // XXX Should log this, not just print.
+ ex.printStackTrace(System.err);
+ }
+
+ /**
+ * Subclasses implement this to take care of individiual requests.
+ * @return A RequestFinisher or null. If null, then no further work is
+ * required on behalf of this request. If a RequestFinisher is returned,
+ * then it is added to a list, and after all requests have been processed,
+ * the finishers in the list have their finish() method invoked on them.
+ * Finishers are invoked in the same order as the requests were.
+ */
+ abstract RequestFinisher handleRequest()
+ throws IOException, FOStoreDatabaseException;
+}
+
+
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestId.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestId.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestId.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestId.java Sun May 22 11:40:13 2005
@@ -0,0 +1,120 @@
+/*
+ * 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.JDOFatalUserException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+* Represents a simple id associated with a request. This is used, for
+* example, to pair up requests and replies: when a Request is written to the
+* store, it is put in a map keyed by RequestId, and when replies are received
+* from the store, they contain a RequestId; this is used to find the
+* corresponding Request which then handles the reply data.
+*
+* @author Dave Bristor
+*/
+class RequestId {
+ // RequestId's are per-pmf; this maps from FOStorePMF to IdFactory.
+ private static HashMap idFactoryTable = new HashMap();
+
+ // The representation of a RequestId. We use a Long so that we can
+ // support them as keys in Maps. Note also the need for hashCode() and
+ // equals() for the same reason.
+ private final Long id;
+
+ // When the server is having catastrophic problems, it should use this as
+ // a request id in the reply it creates.
+ public static final RequestId FAILURE = new RequestId(-1L);
+
+ /** I18N support. */
+ private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+ private RequestId(long id) {
+ this.id = new Long(id);
+ }
+
+ /**
+ * Create a new RequestId by reading it's representation from the input.
+ * @param in DataInput from which representation is read.
+ */
+ RequestId(DataInput in) throws IOException {
+ this.id = new Long(in.readLong());
+ }
+
+ /**
+ * Writes its representation to the output stream.
+ * @param out DataOutput stream to which RequestId's representation is
+ * written.
+ */
+ void write(DataOutput out) throws IOException {
+ out.writeLong(id.longValue());
+ }
+
+ // This is how you allocate yourself a RequestId. Allocates an id from
+ // the factory corresponding to the given PMF.
+ //
+ synchronized static RequestId allocate(FOStorePMF pmf) {
+
+ // IdFactory is in charge of allocating the instances of the
+ // representation of a RequestId.
+ class IdFactory {
+ // Using this might make debug output easier to read:
+ //private long lastAllocated = 0;
+ private long lastAllocated = Long.MIN_VALUE;
+
+ long allocate() {
+ if (lastAllocated == Long.MAX_VALUE) {
+ throw new FOStoreFatalInternalException(
+ RequestId.class, "allocate", // NOI18N
+ msg.msg("ERR_Overflow", new Long(Long.MAX_VALUE))); // NOI18N
+ }
+ return lastAllocated++;
+ }
+ }
+
+ IdFactory f = (IdFactory)idFactoryTable.get(pmf);
+ if (null == f) {
+ f = new IdFactory();
+ idFactoryTable.put(pmf, f);
+ }
+ return new RequestId(f.allocate());
+ }
+
+ /**
+ * Returns true if the other id is equal to this one.
+ * @param other RequestId to which this one is compared.
+ */
+ public boolean equals(Object other) {
+ return id.longValue() == ((RequestId)other).id.longValue();
+ }
+
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ public String toString() {
+ return "ReqId=" + id.toString(); // NOI18N
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestType.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestType.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestType.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RequestType.java Sun May 22 11:40:13 2005
@@ -0,0 +1,146 @@
+/*
+ * 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;
+
+/**
+* Represents a kind of Request. Used to identify request types between
+* client and store; a smaller representation than a Request's
+* java.lang.Class.
+*
+* @author Dave Bristor
+*/
+class RequestType {
+ // We use an Integer so that we can support the requestHandlers HashTable.
+ private final Integer id;
+
+ private static HashMap requestTypes = new HashMap();
+ private static HashMap requestHandlers = new HashMap();
+
+ private static HashMap debug = new HashMap(); // for debugging only
+
+ private static int nextType = 0;
+ static {
+ RequestType rt = null;
+
+ rt = new RequestType(nextType++, ActivateClassRequest.class,
+ ActivateClassHandler.factory);
+
+ rt = new RequestType(nextType++, InsertRequest.class,
+ InsertHandler.factory);
+
+ rt = new RequestType(nextType++, UpdateRequest.class,
+ UpdateHandler.factory);
+
+ rt = new RequestType(nextType++, VerifyRequest.class,
+ VerifyHandler.factory);
+
+ rt = new RequestType(nextType++, DeleteRequest.class,
+ DeleteHandler.factory);
+
+ rt = new RequestType(nextType++, FetchRequest.class,
+ FetchHandler.factory);
+
+ rt = new RequestType(nextType++, GetExtentRequest.class,
+ GetExtentHandler.factory);
+
+ rt = new RequestType(nextType++, GetInstancesRequest.class,
+ GetInstancesHandler.factory);
+
+ rt = new RequestType(nextType++, GetClassRequest.class,
+ GetClassHandler.factory);
+
+ rt = new RequestType(nextType++, CommitRequest.class,
+ CommitHandler.factory);
+
+ rt = new RequestType(nextType++, RollbackRequest.class,
+ RollbackHandler.factory);
+
+ rt = new RequestType(nextType++, CreateOIDRequest.class,
+ CreateOIDHandler.factory);
+
+ rt = new RequestType(nextType++, LoginRequest.class,
+ LoginHandler.factory);
+
+ rt = new RequestType(nextType++, BeginTxRequest.class,
+ BeginTxHandler.factory);
+
+ rt = new RequestType(nextType++, DumpRequest.class,
+ DumpHandler.factory);
+ }
+
+ RequestType(int id, Class requestClass,
+ RequestHandler.HandlerFactory factory) {
+ this.id = new Integer(id);
+ if (null != requestTypes.put(requestClass, this)) {
+ throw new FOStoreFatalInternalException(
+ this.getClass(), "constructor", // NOI18N
+ "duplicate requestClass entry"); // NOI18N
+ }
+
+ if (null != requestHandlers.put(this, factory)) {
+ throw new FOStoreFatalInternalException(
+ this.getClass(), "constructor", // NOI18N
+ "duplicate factory entry"); // NOI18N
+ }
+
+ debug.put(this.id, requestClass);
+ }
+
+ RequestType(DataInput in) throws IOException {
+ this.id = new Integer(in.readInt());
+ }
+
+ void write(DataOutput out) throws IOException {
+ out.writeInt(id.intValue());
+ }
+
+ /**
+ * @return The RequestType corresponding to the given class.
+ */
+ static RequestType get(Class cls) {
+ return (RequestType)requestTypes.get(cls);
+ }
+
+ public int hashCode() {
+ return id.hashCode();
+ }
+
+ public boolean equals (Object other) {
+ return this.id.intValue() == ((RequestType)other).id.intValue();
+ }
+
+ /**
+ * @return The factory that can create a RequestHandler corresponding to
+ * our request type.
+ */
+ RequestHandler.HandlerFactory getHandlerFactory() {
+ return (RequestHandler.HandlerFactory)requestHandlers.get(this);
+ }
+
+ public String toString() {
+ String name = ((Class)(debug.get(id))).getName();
+ name = name.substring(name.lastIndexOf('.')+1);
+ return "ReqType=" + id.toString() + " " + // NOI18N
+ "(" + name + ")"; // NOI18N
+ }
+}
+
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,76 @@
+/*
+ * 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.IOException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+* Process Rollback requests.
+*
+* @author Dave Bristor
+*/
+// This is server-side code. It does not need to live in the client.
+class RollbackHandler extends RequestHandler {
+ /** I18N support. */
+ private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+ private RollbackHandler(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 RollbackHandler(reply, length, con);
+ }};
+
+ /**
+ * Causes RequestHandler.handleRequests to not run finishers when a
+ * RollbackRequest has been found in a message. There's no reason to run
+ * them in such a case, as the rollback will undo their effects anyway.
+ */
+ protected boolean getOkToFinish() {
+ return false;
+ }
+
+
+ RequestFinisher handleRequest()
+ throws IOException, FOStoreDatabaseException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("RollbackHandler.hR"); // NOI18N
+ }
+
+ try {
+ con.rollback();
+ } catch (FOStoreDatabaseException ex) {
+ throw new FOStoreFatalInternalException(
+ this.getClass(), "handleRequest", // NOI18N
+ msg.msg("ERR_RollbackFailed", ex)); // NOI18N
+ }
+
+ con.setOkToReleaseDatabase(true);
+ reply.setStatus(Status.ROLLBACK);
+ return null;
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackRequest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackRequest.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackRequest.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/RollbackRequest.java Sun May 22 11:40:13 2005
@@ -0,0 +1,71 @@
+/*
+ * 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;
+
+/**
+* Represents a request to cause operations since the previous Commit or
+* Rollback request to rollback.
+*
+* @author Dave Bristor
+*/
+//
+// This is client-side code. It does not need to live in the server.
+//
+class RollbackRequest extends AbstractRequest {
+ RollbackRequest(Message m, FOStorePMF pmf) {
+ super(m, pmf);
+ }
+
+ //
+ // Methods from AbstractRequest
+ //
+
+ /**
+ * Provides the information ecessary for a RollbackRequest.
+ * The format of this request is (aside from the request header):
+ * <pre>
+ * empty: that's right, there's nothing here; the request's existence
+ * is alone enough to cause a rollback.
+ * </pre>
+ */
+ protected void doRequestBody() throws IOException {
+ if (logger.isDebugEnabled()) {
+ logger.debug("RollbackRequest.dRB"); // NOI18N
+ }
+ }
+
+ //
+ // Methods from Request
+ //
+
+ /**
+ * This should never be executed. A RollbackRequest causes the reply
+ * data's header's Status value to indicate that the user requested a
+ * rollback, and when the reply handler sees that value, it does not
+ * invoke handleReply on any replies.
+ */
+ public void handleReply(Status status, DataInput in, int length)
+ throws IOException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("RollbackRequest.hR"); // NOI18N
+ }
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ShortTranscriber.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ShortTranscriber.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ShortTranscriber.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/ShortTranscriber.java Sun May 22 11:40:13 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 short values.
+*
+* @author Dave Bristor
+*/
+class ShortTranscriber extends FOStoreTranscriber {
+ private static ShortTranscriber instance = new ShortTranscriber();
+
+ private ShortTranscriber() {}
+
+ static ShortTranscriber getInstance() {
+ return instance;
+ }
+
+ void storeShort(short value, DataOutput out) throws IOException {
+ out.writeShort(value);
+ }
+
+ short fetchShort(DataInput in) throws IOException {
+ return in.readShort();
+ }
+
+ void skip(DataInput in) throws IOException {
+ in.readShort();
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Status.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Status.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Status.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Status.java Sun May 22 11:40:13 2005
@@ -0,0 +1,134 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+* Represents a quick summary of the result of processing a request.
+*
+* @author Dave Bristor
+*/
+class Status {
+ /** I18N support. */
+ private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+ /** Request is being processed. Should be used only by Reply's
+ * constructor, to write a value which will be overwritten once the
+ * requests's actual status is known. */
+ private static final Status UNKNOWN = new Status(-1);
+
+ /** Request was successfully processed. */
+ static final Status OK = new Status(0);
+
+ /** Request succeeded, but with warnings. */
+ static final Status WARN = new Status(1);
+
+ /** Request failed. */
+ static final Status ERROR = new Status(2);
+
+ /** Request failed fatally in server. */
+ static final Status FATAL = new Status(3);
+
+ /** Database rolled back due to user request. */
+ static final Status ROLLBACK = new Status(4);
+
+ /** Could not login to database. */
+ static final Status LOGIN = new Status(5);
+
+ /** Optimistic failure. Verify, delete, or duplicate oid. */
+ static final Status OPTIMISTIC = new Status(6);
+
+ /** Minimum status value. */
+ private static final int MIN_STATUS = -1;
+
+ /** Maximum status value. */
+ private static final int MAX_STATUS = 6;
+
+ /** Status value. */
+ private final int status;
+
+ /**
+ * Used to create the public static final elements.
+ */
+ private Status(int status) {
+ this.status = status;
+ }
+
+ /**
+ * Used to initialize a reply
+ */
+ static void initialize(Reply reply) throws IOException {
+ UNKNOWN.write(reply);
+ }
+
+ /**
+ * Used to 'reconstitute' a Status value from a DataInput.
+ */
+ Status(DataInput in) throws IOException {
+ this.status = in.readInt();
+ if (status < MIN_STATUS || status > MAX_STATUS){
+ throw new FOStoreFatalInternalException(
+ this.getClass(), "constructor(DataInput)", // NOI18N
+ msg.msg("ERR_OutOfRange", new Integer(status), // NOI18N
+ new Integer(MIN_STATUS), new Integer(MAX_STATUS)));
+ }
+ }
+
+ /**
+ * Used to externalize a Status value.
+ */
+ void write(DataOutput out) throws IOException {
+ out.writeInt(status);
+ }
+
+ /**
+ * Returns length of a Status value's representation in bytes.
+ */
+ int getLength() {
+ return 4;
+ }
+
+ /**
+ * Compares this to another Status.
+ */
+ public boolean equals(Object other) {
+ return this.status == ((Status)other).status;
+ }
+
+ public String toString() {
+ String rc = msg.msg("MSG_Invalid"); // NOI18N
+ switch (status) {
+ case -1: rc = msg.msg("MSG_Unknown"); break; // NOI18N
+ case 0: rc = msg.msg("MSG_Ok"); break; // NOI18N
+ case 1: rc = msg.msg("MSG_Warn"); break; // NOI18N
+ case 2: rc = msg.msg("MSG_Error"); break; // NOI18N
+ case 3: rc = msg.msg("MSG_Fatal"); break; // NOI18N
+ case 4: rc = msg.msg("MSG_Rollback"); break; // NOI18N
+ case 5: rc = msg.msg("MSG_Login"); break; // NOI18N
+ case 6: rc = msg.msg("MSG_Optimistic"); break; // NOI18N
+ default: break;
+ }
+ return rc;
+ }
+}
+
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/SubclassSet.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/SubclassSet.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/SubclassSet.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/SubclassSet.java Sun May 22 11:40:13 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.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.HashSet;
+import java.util.Iterator;
+
+import org.netbeans.mdr.persistence.Streamable;
+import org.netbeans.mdr.persistence.StorageException;
+import org.netbeans.mdr.persistence.StorageIOException;
+
+/**
+* Represents a set of CLIDs of subclasses of a given class.
+* <p>
+* This class is <code>public</code> so that it can be used as a
+* <code>Streamable</code> and stored in the database.
+*
+* @author Dave Bristor
+*/
+public class SubclassSet implements Streamable {
+ /** The oid of this list of subclasses. */
+ private OID oid;
+
+ /** List of the clids which represent classes that are subclasses of the
+ * class indicated by the CLID in our oid. */
+ private HashSet clids;
+
+ /**
+ * Given clid is the first entry in the list.
+ */
+ private SubclassSet(OID oid, CLID clid) {
+ this.oid = oid;
+ clids = new HashSet();
+ clids.add(clid);
+ }
+
+ static SubclassSet create(OID oid, CLID clid) {
+ return new SubclassSet(oid, clid);
+ }
+
+ /**
+ * Add the given clid to the list.
+ */
+ void add(CLID clid) {
+ clids.add(clid);
+ }
+
+ /**
+ * @return Iterator over the CLID's in this subclass list.
+ */
+ Iterator iterator() {
+ return clids.iterator();
+ }
+
+ //
+ // Implement Streamable
+ //
+
+ public SubclassSet() { }
+
+ /**
+ * Write this SubclassSet to the given stream.
+ */
+ public void write(OutputStream os) throws StorageException {
+ DataOutputStream dos = new DataOutputStream(os);
+
+ try {
+ oid.write(dos);
+ int size = clids.size();
+ dos.writeInt(size);
+ for (Iterator i = clids.iterator(); i.hasNext();) {
+ CLID clid = (CLID)i.next();
+ clid.write(dos);
+ }
+ } catch (IOException ex) {
+ throw new StorageIOException(ex);
+ }
+ }
+
+ /**
+ * Initialize this SubclassSet from the given stream.
+ */
+ public void read(InputStream is) throws StorageException {
+ DataInputStream dis = new DataInputStream(is);
+ try {
+ this.oid = OID.read(dis);
+ int size = dis.readInt();
+ clids = new HashSet(size);
+ for (int i = 0; i < size; i++) {
+ clids.add(CLID.read(dis));
+ }
+ } catch (IOException ex) {
+ throw new StorageIOException(ex);
+ }
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Tester.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Tester.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Tester.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/Tester.java Sun May 22 11:40:13 2005
@@ -0,0 +1,132 @@
+/*
+ * 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.text.NumberFormat;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+* Provides a relatively convient way to print debug messages.
+*
+* @author Dave Bristor
+*/
+class Tester {
+ static final Log logger = LogFactory.getFactory().getInstance(
+ "org.apache.jdo.impl.fostore"); // NOI18N
+
+ private static boolean threadPrinting =
+ Boolean.getBoolean("org.apache.jdo.impl.fostore.threadprinting");
+
+ private static final NumberFormat nf;
+ static {
+ nf = NumberFormat.getInstance();
+ nf.setMinimumIntegerDigits(4);
+ nf.setMaximumIntegerDigits(4);
+ nf.setMaximumFractionDigits(0);
+ nf.setGroupingUsed(false);
+ }
+
+ // This method checks that TIME is enabled, unlike the other methods.
+ // Reason: it doesn't take an arguments, and therefore the runtime of
+ // calling this is very small (no String args to construct as w/ print
+ // methods).
+ static Object startTime() {
+ Timer timer = new Timer();
+ timer.start();
+ return timer;
+ }
+
+ static void printTime(Object o, String msg) {
+ if (null != o && o instanceof Timer) {
+ Timer timer = (Timer)o;
+ timer.println(msg);
+ }
+ }
+
+ static String toHex(long n, int len) {
+ String rc = Long.toHexString(n);
+ StringBuffer zeroes = new StringBuffer("0000000000000000"); // NOI18N
+ int length = rc.length();
+ if (length > len) {
+ rc = rc.substring(length - len);
+ } else if (len > length) {
+ rc = zeroes.substring(0, len - length) + rc;
+ }
+ return rc;
+ }
+
+ static void dump(String label, byte data[], int length) {
+ dump(label, data, 0, length);
+
+ }
+
+ static void dump(String label, byte data[], int offset, int length) {
+ // Determine number of lines to print
+ final int bytesPerLine = 16;
+ int lines = length / bytesPerLine;
+ if (0 != length % bytesPerLine) {
+ lines++;
+ }
+ int line = 0; // Address at start of line
+
+ int addr = offset;
+ int max = offset + length;
+
+ logger.trace("dumping " + length + " bytes"); // NOI18N
+
+ for (int i = 0; i < lines; i++) {
+ StringBuffer buf = new StringBuffer();
+
+ if (threadPrinting) {
+ buf.append(Thread.currentThread().toString() + ": "); // NOI18N
+ }
+ buf.append(label + " " + nf.format((long)line) + ": "); // NOI18N
+ line += bytesPerLine;
+ for (int j = 0; j < bytesPerLine; j++) {
+ if (addr >= max) {
+ break;
+ } else {
+ buf.append(toHex((long)data[addr], 2) + " "); // NOI18N
+ }
+ addr++;
+ }
+ logger.trace(buf.toString());
+ }
+ }
+
+ static void dump(String label, FOStoreOutput out, int offset, int length) {
+ byte data[] = out.getBuf();
+ dump(label, data, offset, length);
+ }
+
+ static class Timer {
+ long start;
+
+ public void start() {
+ start = System.currentTimeMillis();
+ }
+
+ public void println(String msg) {
+ long end;
+ end = System.currentTimeMillis();
+ System.out.println(msg + ": " + (end - start)); // NOI18N
+ start = end;
+ }
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,211 @@
+/*
+ * 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.Arrays;
+
+import javax.jdo.JDOUserException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+* Process requests to update instances in the datastore.
+*
+* @author Dave Bristor
+*/
+//
+// This is server-side code. It does not need to live in the client.
+//
+class UpdateHandler extends InsertHandler {
+ /** I18N Support */
+ // Note that in this file we're using keys with the "EXC" prefix, but
+ // outside the context of throwing an exception: this is because the
+ // client side will take these messages and put them into exceptions. See
+ // ReplyHandler.handleReplies.
+ private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+ /** Construct a new handler for processing updates.
+ * @param reply the Reply.
+ * @param length the length of data in the stream.
+ * @param con the connection to use.
+ */
+ protected UpdateHandler(Reply reply, int length,
+ FOStoreServerConnection con) {
+
+ super(reply, length, con);
+ }
+
+ static final HandlerFactory factory =
+ new HandlerFactory() {
+ public RequestHandler getHandler(Reply reply, int length,
+ FOStoreServerConnection con) {
+ return new UpdateHandler(reply, length, con);
+ }};
+
+ RequestFinisher handleRequest()
+ throws IOException, FOStoreDatabaseException {
+
+ RequestFinisher rc = null;
+ FOStoreInput in = con.getInputFromClient();
+
+ // True if verify() returns true or datastore transaction.
+ boolean okToUpdate = true;
+
+ // True if verify throws an exception. In that case, okToUpdate
+ // *will* be false.
+ boolean verifyException = true;
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateHandler.hR: begin"); // NOI18N
+ }
+
+ OID oid = null;
+ try {
+ boolean optimistic = in.readBoolean();
+ if (optimistic) {
+ oid = OID.read(in);
+ Block block = readBlock(in);
+ okToUpdate = verify(oid, true, block);
+ }
+ verifyException = false;
+ } catch(DoesNotExistException ex) {
+ okToUpdate = false;
+ reply.writeOID(oid);
+ reply.setStatus(
+ Status.OPTIMISTIC,
+ msg.msg("EXC_OptimisticDoesNotExist", oid)); // NOI18N
+ } catch(Exception ex) {
+ okToUpdate = false;
+ reply.writeOID(oid);
+ reply.setStatus(
+ Status.ERROR,
+ msg.msg("ERR_VerifyException", oid), ex); // NOI18N
+ }
+
+ int length = in.readInt();
+ if (okToUpdate) {
+ // datastore image exists and matches before image
+ rc = super.handleRequest();
+ } else {
+ in.skipBytes(length);
+ if ( ! verifyException) {
+ reply.writeOID(oid);
+ // mismatch between before image and datastore image
+ // status has not yet been set by exception handling
+ reply.setStatus(
+ Status.OPTIMISTIC,
+ msg.msg("EXC_OptimisticVerifyFailed", oid)); // NOI18N
+ }
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateHandler.hR: end"); // NOI18N
+ }
+
+ return rc;
+ }
+
+ /** Verify before image versus database state of an object.
+ * @return true if verify succeeds as per <code>verifyFields</code>.
+ * @param oid OID of object to be verified
+ * @param verifyFields If true, verify that values of the data
+ * corresponding to <code>oid</code> in the database match those in the
+ * given block; if false verify that object corresponding to
+ * <code>oid</code> exists.
+ * @param block Block of data for value verification; may be null if
+ * <code>verifyFields</code> is false.
+ * @throws IOException if stream errors.
+ * @throws FOStoreDatabaseException if any errors in the database.
+ * @throws DoesNotExistException if the object to be updated does not exist.
+ */
+ protected boolean verify(OID oid, boolean verifyFields, Block block)
+ throws IOException, FOStoreDatabaseException, DoesNotExistException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateHandler.verify for: " + oid + // NOI18N
+ ", verifyFields=" + verifyFields); // NOI18N
+ }
+
+ boolean rc = false;
+
+ FOStoreDatabase fodb = con.getDatabase();
+ Block current = (Block)fodb.getIfExists(oid);
+
+ rc = (null != current);
+
+ if (verifyFields) {
+ byte blockData[] = block.getData();
+
+ if (logger.isTraceEnabled()) {
+ Tester.dump("BLK", blockData, blockData.length); // NOI18N
+ }
+
+ // Reset to false so that if we get an error, client won't try to
+ // set status.
+ rc = false;
+
+ if (null == current) {
+ throw new DoesNotExistException();
+ } else {
+ byte currentData[] = current.getData();
+ if (logger.isTraceEnabled()) {
+ logger.debug(
+ "UpdateHandler.verify current data:"); // NOI18N
+ Tester.dump("CUR", currentData, currentData.length); // NOI18N
+ }
+
+ // XXX TBD Compare and report based on field values
+ rc = Arrays.equals(blockData, currentData);
+ }
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateHandler.verify returns: " + rc); // NOI18N
+ }
+
+ return rc;
+ }
+
+ /**
+ * Thrown by {@link UpdateHandler#verify} if an object which should exist
+ * in the database, does not.
+ */
+ private class DoesNotExistException extends Exception { }
+
+ /** Replace a block in the database.
+ * @see InsertHandler#updateDB
+ * @param provOID provisional OID.
+ * @param realOID OID to use as key in the database.
+ * @param block Block to be inserted in database.
+ * @param db Database into which block is replaced.
+ * @throws IOException for stream errors.
+ * @throws FOStoreDatabaseException for any database error except for object not found.
+ */
+ protected void updateDB(OID realOID, OID provOID, Block block,
+ FOStoreDatabase db)
+ throws IOException, FOStoreDatabaseException {
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateHandler.updateDb: " + realOID); // NOI18N
+ }
+ db.replace(realOID, block);
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateRequest.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateRequest.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateRequest.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/UpdateRequest.java Sun May 22 11:40:13 2005
@@ -0,0 +1,144 @@
+/*
+ * Copyright 2005 The Apache Software Foundation.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.jdo.impl.fostore;
+
+import java.io.DataInput;
+import java.io.IOException;
+import java.util.BitSet;
+
+import javax.jdo.PersistenceManager;
+import javax.jdo.Transaction;
+
+import org.apache.jdo.model.jdo.PersistenceModifier;
+import org.apache.jdo.state.StateManagerInternal;
+import org.apache.jdo.util.I18NHelper;
+
+
+
+/**
+ * Represents a request to change one or more fields of a persistent object in
+ * the store.
+ *
+ * @author Dave Bristor
+ */
+//
+// This is client-side code. It does not need to live in the server.
+//
+class UpdateRequest extends InsertRequest {
+ /** Fields which are to be updated. */
+ private final BitSet loadedFields;
+
+ /** Fields which are to be verified in database, in case of
+ * optimistic transaction. */
+ private final BitSet dirtyFields;
+
+ /** If true, update happens in context of an optimistic transaction. */
+ private final boolean optimistic;
+
+ UpdateRequest(StateManagerInternal sm, Message m, FOStorePMF pmf,
+ BitSet loadedFields, BitSet dirtyFields, boolean optimistic) {
+
+ super(sm, m, pmf);
+ this.loadedFields = loadedFields;
+ this.dirtyFields = dirtyFields;
+ this.optimistic = optimistic;
+ }
+
+ //
+ // Methods from AbstractRequest
+ //
+
+ /**
+ * Provides the information necessary to do an UpdateRequest.
+ * The format of this request is (aside from the request header):
+ * <pre>
+ * optimistic: boolean
+ * oid: OID
+ * data block
+ * length: int
+ * InsertRequest's doRequestBody - written data
+ * </pre>
+ * The oid and data block are written only if optimistic is true.
+ * @see AbstractRequest#doRequestBody
+ */
+ protected void doRequestBody() throws IOException {
+ OID oid = (OID)sm.getInternalObjectId();
+ if (oid.isProvisional()) {
+ throw new FOStoreFatalInternalException(
+ this.getClass(), "doRequestBody", // NOI18N
+ msg.msg("ERR_OidIsProvisional", oid)); // NOI18N
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateRequest.dRB: begin: " + optimistic); // NOI18N
+ }
+
+ out.writeBoolean(optimistic);
+
+ if (optimistic) {
+ oid.write(out);
+ // XXX For now, verify the values of all the fields.
+ writeBlock(jdoClass.getPersistentFieldNumbers(), true);
+ }
+
+ // Save space to write the length of the data written by
+ // InsertRequest. The reason is, that on the Handler side, if we're
+ // running an optimistic transaction and the verify fails, we just
+ // want to skip over InsertRequest's bytes.
+ //
+ int lengthPos = out.getPos();
+ out.writeInt(LENGTH_COOKIE);
+ int startPos = out.getPos();
+
+ super.doRequestBody();
+
+ int currentPos = out.getPos();
+ int length = currentPos - startPos;
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateRequest.dRB: length=" + length); // NOI18N
+ }
+ out.setPos(lengthPos);
+ out.writeInt(length);
+ out.setPos(currentPos);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateRequest.dRB: end"); // NOI18N
+ }
+ }
+
+ //
+ // Methods from Request
+ //
+
+ /**
+ * Handles reply data from an UpdateReply.
+ * The format of this reply is
+ * <pre>
+ * oid: OID
+ * </pre>
+ */
+ public void handleReply(Status status, DataInput in, int length)
+ throws IOException {
+
+ OID replyOid = OID.read(in);
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("UpdateRequest.hR: " + replyOid + // NOI18N
+ ", " + status); // NOI18N
+ }
+ }
+}
Added: incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/VerifyHandler.java
URL: http://svn.apache.org/viewcvs/incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/VerifyHandler.java?rev=171355&view=auto
==============================================================================
--- incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/VerifyHandler.java (added)
+++ incubator/jdo/trunk/fostore20/src/java/org/apache/jdo/impl/fostore/VerifyHandler.java Sun May 22 11:40:13 2005
@@ -0,0 +1,97 @@
+/*
+ * 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.Arrays;
+
+import javax.jdo.JDOUserException;
+
+import org.apache.jdo.util.I18NHelper;
+
+
+/**
+* Process requests to verify instances in the datastore.
+*
+* @author Dave Bristor
+*/
+//
+// This is server-side code. It does not need to live in the client.
+//
+class VerifyHandler extends UpdateHandler {
+ /** I18N Support */
+ // Note that in this file we're using keys with the "EXC" prefix, but
+ // outside the context of throwing an exception: this is because the
+ // client side will take these messages and put them into exceptions. See
+ // ReplyHandler.handleReplies.
+ private static final I18NHelper msg = I18NHelper.getInstance(I18N.NAME);
+
+ private VerifyHandler(Reply reply, int length,
+ FOStoreServerConnection con) {
+
+ super(reply, length, con);
+ }
+
+ static final HandlerFactory factory =
+ new HandlerFactory() {
+ public RequestHandler getHandler(Reply reply, int length,
+ FOStoreServerConnection con) {
+ return new VerifyHandler(reply, length, con);
+ }};
+
+ /**
+ * Verify that instance exists and/or its values match those in the
+ * client.
+ */
+ RequestFinisher handleRequest()
+ throws IOException, FOStoreDatabaseException {
+
+ FOStoreInput in = con.getInputFromClient();
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("VerifyHandler.hR: begin"); // NOI18N
+ }
+
+ boolean rc = false;
+
+ OID oid = OID.read(in);
+ boolean verifyFields = in.readBoolean();
+
+ try {
+ if (verifyFields) {
+ Block block = readBlock(in);
+ rc = verify(oid, true, block);
+ } else {
+ rc = verify(oid, false, null);
+ }
+ reply.writeBoolean(rc);
+ reply.setStatus(Status.OK);
+ } catch (Exception ex) {
+ reply.writeBoolean(false);
+ reply.setStatus(Status.ERROR,
+ msg.msg("ERR_VerifyException", oid, ex)); // NOI18N
+ }
+
+ if (logger.isDebugEnabled()) {
+ logger.debug("VerifyHandler.hR: end, rc=" + rc); // NOI18N
+ }
+
+ return null;
+ }
+}