001: package org.mandarax.zkb;
002:
003: /*
004: * Copyright (C) 1999-2004 <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</a>
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation; either
009: * version 2 of the License, or (at your option) any later version.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: *
016: * You should have received a copy of the GNU Lesser General Public
017: * License along with this library; if not, write to the Free Software
018: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
019: */
020:
021: import java.util.*;
022: import javax.sql.DataSource;
023: import org.mandarax.kernel.*;
024:
025: /**
026: * An abstract OPS implementation.
027: * @author <A href="http://www-ist.massey.ac.nz/JBDietrich" target="_top">Jens Dietrich</A>
028: * @version 3.4 <7 March 05>
029: * @since 2.2
030: */
031: public abstract class AbstractOPS implements ObjectPersistencyService {
032:
033: protected Map urisByObject = new IdentityHashMap();
034: protected Map objectsByUri = new HashMap();
035:
036: // prefixes for primitives
037: public static final String BOOLEAN = "boolean:";
038: public static final String BYTE = "byte:";
039: public static final String CHAR = "char:";
040: public static final String DOUBLE = "double:";
041: public static final String FLOAT = "float:";
042: public static final String INT = "int:";
043: public static final String LONG = "long:";
044: public static final String SHORT = "short:";
045: public static final String STRING = "string:";
046: public static final String OBJECT = "object:java:";
047:
048: /**
049: * Get the extension of the associated files.
050: * @return a file extension
051: */
052: public abstract String getExtension();
053:
054: /**
055: * Generate an URI for an object.
056: * @param obj an object
057: * @return an URI
058: */
059: public synchronized String createName(Object obj) {
060: if (obj instanceof Integer)
061: return INT + String.valueOf(obj);
062: else if (obj instanceof String)
063: return STRING + obj;
064: else if (obj instanceof Boolean)
065: return BOOLEAN + String.valueOf(obj);
066: else if (obj instanceof Character)
067: return CHAR + String.valueOf(obj);
068: else if (obj instanceof Double)
069: return DOUBLE + String.valueOf(obj);
070: else if (obj instanceof Float)
071: return FLOAT + String.valueOf(obj);
072: else if (obj instanceof Long)
073: return LONG + String.valueOf(obj);
074: else if (obj instanceof Short)
075: return SHORT + String.valueOf(obj);
076: else if (obj instanceof Byte)
077: return BYTE + String.valueOf(obj);
078: else {
079: // old code (prior to 3.2)
080: /*
081: StringBuffer buf = new StringBuffer();
082: buf.append(OBJECT);
083: buf.append(getExtension());
084: buf.append(":");
085: String type = getType(obj);
086: buf.append(type);
087: buf.append("/id=");
088: buf.append(getCounter(type));
089: return buf.toString();
090: */
091: // changes in 3.2: there have been some problems with inconsistent IDs
092: // we cannot reproduce them, but for now use less descriptive ids which are
093: // unique
094: return new StringBuffer().append(OBJECT).append(
095: getType(obj)).append("/id=").append(
096: new java.rmi.server.UID()).toString();
097: }
098: }
099:
100: /**
101: * Get the type (name) of an object.
102: * @param obj an object
103: * @return the type name
104: */
105: private String getType(Object obj) {
106: if (obj instanceof Predicate)
107: return "predicate";
108: if (obj instanceof Function)
109: return "function";
110: if (obj instanceof ConstantTerm)
111: return "constant_term";
112: if (obj instanceof ComplexTerm)
113: return "complex_term";
114: if (obj instanceof VariableTerm)
115: return "variable_term";
116: if (obj instanceof Prerequisite)
117: return "prerequisite";
118: if (obj instanceof Fact)
119: return "fact";
120: if (obj instanceof Rule)
121: return "rule";
122: if (obj instanceof Query)
123: return "query";
124: if (obj instanceof ClauseSet)
125: return "clause set";
126: if (obj instanceof DataSource)
127: return "data source";
128:
129: return obj == null ? "null" : obj.getClass().getName();
130: }
131:
132: /**
133: * Get the class (name) of an object.
134: * We return some top-level superclasses in order to improve readability
135: * of the files.
136: * @param obj an object
137: * @return the class
138: */
139: private Class getClass(Object obj) {
140: if (obj instanceof Predicate)
141: return Predicate.class;
142: if (obj instanceof Function)
143: return Function.class;
144: if (obj instanceof ConstantTerm)
145: return ConstantTerm.class;
146: if (obj instanceof ComplexTerm)
147: return ComplexTerm.class;
148: if (obj instanceof VariableTerm)
149: return VariableTerm.class;
150: if (obj instanceof Prerequisite)
151: return Prerequisite.class;
152: if (obj instanceof Fact)
153: return Fact.class;
154: if (obj instanceof Rule)
155: return Rule.class;
156: if (obj instanceof ClauseSet)
157: return ClauseSet.class;
158: if (obj instanceof DataSource)
159: return DataSource.class;
160:
161: return obj == null ? null : obj.getClass();
162: }
163:
164: /**
165: * Bind an object to a name (uri).
166: * @param uri an uri
167: * @param obj an object
168: */
169: public synchronized void bind(String uri, Object obj) {
170: if (!isPrimitive(obj)) {
171: objectsByUri.put(uri, obj);
172: urisByObject.put(obj, uri);
173: }
174: }
175:
176: /**
177: * Indicates whether an object is primitive.
178: * @param obj an object.
179: * @return true if the object is a primitive wrapper or a string
180: */
181: private boolean isPrimitive(Object obj) {
182: return obj instanceof Number || obj instanceof String
183: || obj instanceof Boolean || obj instanceof Character;
184: }
185:
186: /**
187: * Find an object. If the object is not yet registered, bind it
188: * using the generated name.
189: * @param obj an object
190: */
191: public synchronized String findOrBind(Object obj) {
192: String uri = null;
193: if ((uri = (String) urisByObject.get(obj)) == null) {
194: uri = createName(obj);
195: bind(uri, obj);
196: }
197: return uri;
198: }
199:
200: /**
201: * Unbind the name (uri).
202: * @param uri an uri
203: */
204: public synchronized void unbind(String uri) {
205: Object obj = lookup(uri);
206: if (obj != null)
207: urisByObject.remove(obj);
208: objectsByUri.remove(uri);
209: }
210:
211: /**
212: * Get an object by name.
213: * @param uri an uri
214: * @return obj an object
215: */
216: public synchronized Object lookup(String uri) {
217: if (uri.startsWith(OBJECT)) {
218: // object - proper look up
219: return objectsByUri.get(uri);
220: } else {
221: // primitive - decode
222: if (uri.startsWith(INT))
223: return Integer.valueOf(uri.substring(INT.length()));
224: else if (uri.startsWith(STRING))
225: return uri.substring(STRING.length());
226: else if (uri.startsWith(BOOLEAN))
227: return Boolean.valueOf(uri.substring(BOOLEAN.length()));
228: else if (uri.startsWith(CHAR))
229: return new Character(uri.substring(CHAR.length())
230: .charAt(0));
231: else if (uri.startsWith(DOUBLE))
232: return Double.valueOf(uri.substring(DOUBLE.length()));
233: else if (uri.startsWith(FLOAT))
234: return Float.valueOf(uri.substring(FLOAT.length()));
235: else if (uri.startsWith(LONG))
236: return Long.valueOf(uri.substring(LONG.length()));
237: else if (uri.startsWith(SHORT))
238: return Short.valueOf(uri.substring(SHORT.length()));
239: else if (uri.startsWith(BYTE))
240: return Byte.valueOf(uri.substring(BYTE.length()));
241: else
242: return null;
243:
244: }
245: }
246:
247: /**
248: * Reverse a map (flip keys and values).
249: * @param originalMap the map to be reversed
250: * @param reversedMap an empty map
251: */
252: protected synchronized void reverseMap(Map originalMap,
253: Map reversedMap) {
254: for (Iterator iter = originalMap.entrySet().iterator(); iter
255: .hasNext();) {
256: Map.Entry nextEntry = (Map.Entry) iter.next();
257: reversedMap.put(nextEntry.getValue(), nextEntry.getKey());
258: }
259: }
260:
261: /**
262: * Reset the state.
263: */
264: public synchronized void reset() {
265: urisByObject.clear();
266: objectsByUri.clear();
267: }
268: }
|