| /* |
| * 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 |
| * above <code>meta</code>, or <code>meta</code> 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; |
| } |
| } |
| } |