XML Store
Simple XML store using the common OpenJPA runtime system as a front end.
openjpa-2.2.2.orig/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLStore.java 0000644 0000000 0000000 00000012230 12133327264 026603 0 ustar /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.openjpa.xmlstore; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; import org.apache.openjpa.meta.ClassMetaData; /** * Represents a store of object data encoded in XML. This store only allows * one datastore transaction to proceed at a time. File I/O errors can put * this store into an invalid state. */ public class XMLStore { private final XMLConfiguration _conf; // each key in the map is a least-derived class metadata object, and each // value is a map of oids to object datas representing the instances of // that class, including subclasses private final Map _metaOidMaps = new HashMap(); // store gets locked during transactions private boolean _locked; /** * Constructor; supply configuration. */ public XMLStore(XMLConfiguration conf) { _conf = conf; } /** * Return the data for the given oid, or null if it does not exist. */ public synchronized ObjectData getData(ClassMetaData meta, Object oid) { meta = getLeastDerived(meta); return (ObjectData) getMap(meta).get(oid); } /** * Return all datas for the base class of the given type. */ public synchronized ObjectData[] getData(ClassMetaData meta) { meta = getLeastDerived(meta); Collection vals = getMap(meta).values(); return (ObjectData[]) vals.toArray(new ObjectData[vals.size()]); } /** * Returns the map of oids to object datas for the given least-derived type. */ private Map getMap(ClassMetaData meta) { Map m = (Map) _metaOidMaps.get(meta); if (m != null) return m; // load datas from file and cache them Collection datas = _conf.getFileHandler().load(meta); m = new HashMap(datas.size()); for (Iterator itr = datas.iterator(); itr.hasNext();) { ObjectData data = (ObjectData) itr.next(); m.put(data.getId(), data); } _metaOidMaps.put(meta, m); return m; } /** * Return the least-derived metadata in the inheritance chain * abovemeta
, or meta
if it is a
* least-derived metadata.
*/
private static ClassMetaData getLeastDerived(ClassMetaData meta) {
while (meta.getPCSuperclass() != null)
meta = meta.getPCSuperclassMetaData();
return meta;
}
/**
* Begin a datastore transaction. Obtains an exclusive write lock on the
* store.
*/
public synchronized void beginTransaction() {
// lock store
while (_locked)
try {
wait();
} catch (InterruptedException ie) {
}
_locked = true;
}
/**
* End the datastore transaction.
*
* @param updates {@link ObjectData} instances to insert or update
* @param deletes {@link ObjectData} instances to delete
*/
public synchronized void endTransaction(Collection updates,
Collection deletes) {
// track dirty types
Set dirty = new HashSet();
try {
// commit updates
if (updates != null) {
for (Iterator itr = updates.iterator(); itr.hasNext();) {
ObjectData data = (ObjectData) itr.next();
ClassMetaData meta = getLeastDerived(data.getMetaData());
getMap(meta).put(data.getId(), data);
dirty.add(meta);
}
}
// commit deletes
if (deletes != null) {
for (Iterator itr = deletes.iterator(); itr.hasNext();) {
ObjectData data = (ObjectData) itr.next();
ClassMetaData meta = getLeastDerived(data.getMetaData());
getMap(meta).remove(data.getId());
dirty.add(meta);
}
}
// write changes to dirty extents back to file
XMLFileHandler fh = _conf.getFileHandler();
for (Iterator itr = dirty.iterator(); itr.hasNext();) {
ClassMetaData meta = (ClassMetaData) itr.next();
fh.store(meta, getMap(meta).values());
}
}
finally {
// unlock store
notify();
_locked = false;
}
}
}
openjpa-2.2.2.orig/openjpa-xmlstore/src/main/java/org/apache/openjpa/xmlstore/XMLFileHandler.java 0000644 0000000 0000000 00000060147 12133327264 027676 0 ustar /*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.openjpa.xmlstore;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.io.Writer;
import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.security.AccessController;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import javax.xml.parsers.SAXParser;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;
import org.apache.openjpa.enhance.PCRegistry;
import org.apache.openjpa.lib.util.Base16Encoder;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.xml.XMLFactory;
import org.apache.openjpa.lib.xml.XMLWriter;
import org.apache.openjpa.meta.ClassMetaData;
import org.apache.openjpa.meta.FieldMetaData;
import org.apache.openjpa.meta.JavaTypes;
import org.apache.openjpa.util.Id;
import org.apache.openjpa.util.InternalException;
import org.apache.openjpa.util.OpenJPAException;
import org.apache.openjpa.util.StoreException;
import org.apache.openjpa.util.UnsupportedException;
/**
* Stores {@link ObjectData} objects by serializing a collection
* of them into and out of an XML file.
*/
public class XMLFileHandler {
private final XMLConfiguration _conf;
/**
* Constructor; supply configuration.
*/
public XMLFileHandler(XMLConfiguration conf) {
_conf = conf;
}
/**
* Loads all instances of meta
into a list of objects.
* The given meta
must represent a least-derived
* persistence-capable type.
*/
public Collection load(ClassMetaData meta) {
File f = getFile(meta);
if (!(AccessController.doPrivileged(
J2DoPrivHelper.existsAction(f))).booleanValue() ||
(AccessController.doPrivileged(
J2DoPrivHelper.lengthAction(f))).longValue() == 0)
return Collections.EMPTY_SET;
try {
return read(f);
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
throw new StoreException(e);
}
}
/**
* Read a collection of {@link ObjectData}s from the contents of the
* given file.
*/
private Collection read(File f)
throws Exception {
// parse the file and return the objects it contains
SAXParser parser = XMLFactory.getSAXParser(false, false);
ObjectDataHandler handler = new ObjectDataHandler(_conf);
parser.parse(f, handler);
return handler.getExtent();
}
/**
* Returns a {@link File} object that meta
lives
* in. This implementation creates a filename from the full class
* name of the type identified by meta
, and returns
* a {@link File} object that has this filename and whose base
* directory is the URL identified by the ConnectionURL
* configuration property.
*/
private File getFile(ClassMetaData meta) {
if (_conf.getConnectionURL() == null) {
throw new InternalException("Invalid ConnectionURL");
}
File baseDir = new File(_conf.getConnectionURL());
return new File(baseDir, meta.getDescribedType().getName());
}
/**
* Stores all instances in datas
into the appropriate file,
* as dictated by meta
.
*
* @param meta the least-derived type of the instances being stored
* @param datas a collection of {@link ObjectData} instances, each
* of which represents an object of type meta
*/
public void store(ClassMetaData meta, Collection datas) {
if (meta.getPCSuperclass() != null)
throw new InternalException();
File f = getFile(meta);
if (!(AccessController.doPrivileged(
J2DoPrivHelper.existsAction(f.getParentFile()))).booleanValue())
AccessController.doPrivileged(
J2DoPrivHelper.mkdirsAction(f.getParentFile()));
FileWriter fw = null;
try {
fw = new FileWriter(f);
write(datas, fw);
} catch (OpenJPAException ke) {
throw ke;
} catch (Exception e) {
throw new StoreException(e);
} finally {
if (fw != null)
try {
fw.close();
} catch (IOException ioe) {
}
}
}
/**
* Write the given collection of {@link ObjectData}s to the given file.
*/
private void write(Collection datas, FileWriter fw)
throws Exception {
// create an XML pretty printer to write out the objects
Writer out = new XMLWriter(fw);
// start the file; the root node is an "extent"
out.write("");
out.write("