001: /*
002: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
004: *
005: * This program is free software; you can redistribute it and/or
006: * modify it under the terms of the GNU General Public License version
007: * 2 only, as published by the Free Software Foundation.
008: *
009: * This program is distributed in the hope that it will be useful, but
010: * WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
012: * General Public License version 2 for more details (a copy is
013: * included at /legal/license.txt).
014: *
015: * You should have received a copy of the GNU General Public License
016: * version 2 along with this work; if not, write to the Free Software
017: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
018: * 02110-1301 USA
019: *
020: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
021: * Clara, CA 95054 or visit www.sun.com if you need additional
022: * information or have any questions.
023: */
024:
025: package com.sun.midp.jump.push.executive.persistence;
026:
027: import com.sun.jump.module.contentstore.JUMPData;
028: import com.sun.jump.module.contentstore.JUMPNode;
029: import com.sun.jump.module.contentstore.JUMPStoreHandle;
030: import java.io.IOException;
031:
032: /**
033: * Abstracts transaction-like operations on the content
034: * store which need store handle.
035: */
036: public final class StoreOperationManager {
037: /**
038: * Abstracts an operation that should be perfomed with
039: * exclusive lock on the content store.
040: */
041: public interface Operation {
042: /**
043: * Performs an operation with exclusive lock on the content store.
044: *
045: * Implementations shouldn't keep the <code>storeHandle</code>
046: * passed out of <code>perform</code> method: the very moment
047: * <code>perform</code> quits, store handle gets invalidated.
048: *
049: * @param storeHandle exclusively locked store handle
050: *
051: * @return abstract result of operation
052: *
053: * @throws IOException if IO fails
054: */
055: Object perform(JUMPStoreHandle storeHandle) throws IOException;
056: }
057:
058: /**
059: * Adapter to <code>JUMPContentStore</code>.
060: *
061: * Actually, this adapter just grants necessary visibility to the methods.
062: */
063: public interface ContentStore {
064: /**
065: * Opens the content store in exclusive mode.
066: *
067: * @param accessExclusive controls exclusiveness of access
068: *
069: * @return store handle
070: *
071: * @throws IOException if IO fails
072: */
073: JUMPStoreHandle open(boolean accessExclusive);
074:
075: /**
076: * Closes a handle.
077: *
078: * @param storeHandle handle to close
079: */
080: void close(JUMPStoreHandle storeHandle);
081: }
082:
083: /** Content store adapter to operate on. */
084: private final ContentStore contentStore;
085:
086: /**
087: * Constructs an instance of manager.
088: *
089: * @param contentStore content store to use
090: */
091: public StoreOperationManager(final ContentStore contentStore) {
092: this .contentStore = contentStore;
093: }
094:
095: /**
096: * Performs an operation on the content store keeping an exclsuive lock.
097: *
098: * Whatever outcome of the operation is, the exclusive lock is released.
099: *
100: * @param operation operation to perform
101: * @param accessExclusive controls exclusiveness of access
102: *
103: * @return abstract result of the operation
104: *
105: * @throws IOException if IO fails
106: */
107: public Object doOperation(final boolean accessExclusive,
108: final Operation operation) throws IOException {
109: final JUMPStoreHandle storeHandle = contentStore
110: .open(accessExclusive);
111: try {
112: return operation.perform(storeHandle);
113: } finally {
114: contentStore.close(storeHandle);
115: }
116: }
117:
118: /**
119: * Gets a node.
120: *
121: * This method is just a wrapper around the corresponding content store API.
122: *
123: * @param uri URI of the node to get
124: *
125: * @return reference to a node
126: *
127: * @throws IOException if IO fails
128: */
129: public JUMPNode getNode(final String uri) throws IOException {
130: return (JUMPNode) doOperation(false, new Operation() {
131: public Object perform(final JUMPStoreHandle storeHandle)
132: throws IOException {
133: return storeHandle.getNode(uri);
134: }
135: });
136: }
137:
138: /**
139: * Safely updates a data node.
140: *
141: * Safely update means that node is either updated (if it exists already)
142: * or created afresh.
143: *
144: * The exclusive lock is obtained and held while operation is running and
145: * thus the content store should be in unlocked state.
146: *
147: * @param uri URI of the node to get
148: * @param data data to put
149: *
150: * @throws IOException if IO fails
151: */
152: public void safelyUpdateDataNode(final String uri,
153: final JUMPData data) throws IOException {
154: doOperation(true, new Operation() {
155: public Object perform(final JUMPStoreHandle storeHandle)
156: throws IOException {
157: if (doesNodeExist(storeHandle, uri)) {
158: storeHandle.updateDataNode(uri, data);
159: } else {
160: storeHandle.createDataNode(uri, data);
161: }
162: return null;
163: }
164: });
165: }
166:
167: /**
168: * Safely deletes a data node.
169: *
170: * Safely deletion means that node is deleted if it is present.
171: *
172: * The exclusive lock is obtained and held while operation is running and
173: * thus the content store should be in unlocked state.
174: *
175: * @param uri URI of the node to delete
176: *
177: * @throws IOException if IO fails
178: */
179: public void safelyDeleteDataNode(final String uri)
180: throws IOException {
181: doOperation(true, new Operation() {
182: public Object perform(final JUMPStoreHandle storeHandle)
183: throws IOException {
184: if (doesNodeExist(storeHandle, uri)) {
185: storeHandle.deleteNode(uri);
186: }
187: return null;
188: }
189: });
190: }
191:
192: /**
193: * Checks if the data node with the given name already exists.
194: *
195: * @param storeHandle content store handle
196: * @param uri node's URI
197: *
198: * @return <code>true</code> iff the node exists
199: *
200: * @throws IOException if IO fails.
201: */
202: private static boolean doesNodeExist(
203: final JUMPStoreHandle storeHandle, final String uri)
204: throws IOException {
205: final JUMPNode.Data node = (JUMPNode.Data) storeHandle
206: .getNode(uri);
207: return (node != null);
208: }
209: }
|