Package org.apache.isis.runtimes.dflt.objectstores.xml

Source Code of org.apache.isis.runtimes.dflt.objectstores.xml.XmlObjectStore

/*
*  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.isis.runtimes.dflt.objectstores.xml;

import java.text.MessageFormat;
import java.util.List;

import org.apache.log4j.Logger;

import org.apache.isis.core.commons.config.ConfigurationConstants;
import org.apache.isis.core.commons.config.IsisConfiguration;
import org.apache.isis.core.commons.debug.DebugBuilder;
import org.apache.isis.core.commons.ensure.Assert;
import org.apache.isis.core.commons.exceptions.IsisException;
import org.apache.isis.core.commons.xml.XmlFile;
import org.apache.isis.core.metamodel.adapter.ObjectAdapter;
import org.apache.isis.core.metamodel.adapter.ResolveState;
import org.apache.isis.core.metamodel.adapter.oid.Oid;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacet;
import org.apache.isis.core.metamodel.facets.collections.modify.CollectionFacetUtils;
import org.apache.isis.core.metamodel.facets.object.encodeable.EncodableFacet;
import org.apache.isis.core.metamodel.spec.ObjectSpecification;
import org.apache.isis.core.metamodel.spec.SpecificationLoader;
import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.clock.Clock;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.commands.XmlCreateObjectCommand;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.commands.XmlDestroyObjectCommand;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.commands.XmlUpdateObjectCommand;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.CollectionData;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.Data;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.DataManager;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.ObjectData;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.ObjectDataVector;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.ReferenceVector;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.xml.XmlDataManager;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.data.xml.XmlFileUtil;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.services.ServiceManager;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.services.xml.XmlServiceManager;
import org.apache.isis.runtimes.dflt.objectstores.xml.internal.version.FileVersion;
import org.apache.isis.runtimes.dflt.runtime.persistence.ObjectNotFoundException;
import org.apache.isis.runtimes.dflt.runtime.persistence.PersistorUtil;
import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.ObjectStore;
import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.CreateObjectCommand;
import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.DestroyObjectCommand;
import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.PersistenceCommand;
import org.apache.isis.runtimes.dflt.runtime.persistence.objectstore.transaction.SaveObjectCommand;
import org.apache.isis.runtimes.dflt.runtime.persistence.oidgenerator.simple.SerialOid;
import org.apache.isis.runtimes.dflt.runtime.persistence.query.PersistenceQueryBuiltIn;
import org.apache.isis.runtimes.dflt.runtime.system.context.IsisContext;
import org.apache.isis.runtimes.dflt.runtime.system.persistence.AdapterManager;
import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceQuery;
import org.apache.isis.runtimes.dflt.runtime.system.persistence.PersistenceSession;
import org.apache.isis.runtimes.dflt.runtime.transaction.ObjectPersistenceException;

public class XmlObjectStore implements ObjectStore {

    private static final Logger LOG = Logger.getLogger(XmlObjectStore.class);
    private static final String XMLOS_DIR = ConfigurationConstants.ROOT + "xmlos.dir";
    private final DataManager dataManager;
    private final ServiceManager serviceManager;
    private boolean isFixturesInstalled;

    public XmlObjectStore(final IsisConfiguration configuration) {
        final String charset = XmlFileUtil.lookupCharset(configuration);
        final String directory = configuration.getString(XMLOS_DIR, "xml/objects");
        final XmlFile xmlFile = new XmlFile(charset, directory);
        dataManager = new XmlDataManager(xmlFile);
        serviceManager = new XmlServiceManager(xmlFile);
        serviceManager.loadServices();
    }

    public XmlObjectStore(final DataManager dataManager, final ServiceManager serviceManager) {
        this.dataManager = dataManager;
        this.serviceManager = serviceManager;
        serviceManager.loadServices();
    }

    // /////////////////////////////////////////////////////////
    // name
    // /////////////////////////////////////////////////////////

    @Override
    public String name() {
        return "XML";
    }

    // /////////////////////////////////////////////////////////
    // close
    // /////////////////////////////////////////////////////////

    @Override
    public void close() {
        LOG.info("close " + this);
    }

    // /////////////////////////////////////////////////////////
    // reset
    // /////////////////////////////////////////////////////////

    @Override
    public void reset() {
    }

    // /////////////////////////////////////////////////////////
    // init, shutdown, finalize
    // /////////////////////////////////////////////////////////

    @Override
    public boolean hasInstances(final ObjectSpecification cls) {
        LOG.debug("checking instance of " + cls);
        final ObjectData data = new ObjectData(cls, null, null);
        return dataManager.numberOfInstances(data) > 0;
    }

    @Override
    public void open() throws ObjectPersistenceException {
        isFixturesInstalled = dataManager.isFixturesInstalled();
    }

    @Override
    public boolean isFixturesInstalled() {
        return isFixturesInstalled;
    }

    private void initObject(final ObjectAdapter object, final ObjectData data) {
        if (object.getResolveState().canChangeTo(ResolveState.RESOLVING)) {
            PersistorUtil.start(object, ResolveState.RESOLVING);

            final List<ObjectAssociation> fields = object.getSpecification().getAssociations();
            for (int i = 0; i < fields.size(); i++) {
                final ObjectAssociation field = fields.get(i);
                if (field.isNotPersisted()) {
                    continue;
                }

                final ObjectSpecification fieldSpecification = field.getSpecification();
                if (fieldSpecification.isEncodeable()) {
                    final EncodableFacet encoder = fieldSpecification.getFacet(EncodableFacet.class);
                    ObjectAdapter value;
                    final String valueData = data.value(field.getId());
                    if (valueData != null) {
                        if (valueData.equals("NULL")) {
                            value = null;
                        } else {
                            value = encoder.fromEncodedString(valueData);
                        }
                        ((OneToOneAssociation) field).initAssociation(object, value);
                    }
                } else if (field.isOneToManyAssociation()) {
                    initObjectSetupCollection(object, data, field);
                } else if (field.isOneToOneAssociation()) {
                    initObjectSetupReference(object, data, field);
                }
            }
            object.setOptimisticLock(data.getVersion());
            PersistorUtil.end(object);
        }
    }

    private void initObjectSetupReference(final ObjectAdapter object, final ObjectData data, final ObjectAssociation field) {
        final SerialOid referenceOid = (SerialOid) data.get(field.getId());
        LOG.debug("setting up field " + field + " with " + referenceOid);
        if (referenceOid == null) {
            return;
        }

        final Data fieldData = dataManager.loadData(referenceOid);

        if (fieldData == null) {
            final ObjectAdapter adapter = getPersistenceSession().recreateAdapter(referenceOid, field.getSpecification());
            if (!adapter.getResolveState().isDestroyed()) {
                adapter.changeState(ResolveState.DESTROYED);
            }
            ((OneToOneAssociation) field).initAssociation(object, adapter);

            LOG.warn("No data found for " + referenceOid + " so field '" + field.getName() + "' not set in object '" + object.titleString() + "'");
        } else {
            final ObjectAdapter reference = getPersistenceSession().recreateAdapter(referenceOid, specFor(fieldData));
            ((OneToOneAssociation) field).initAssociation(object, reference);
        }

        /*
         * if (loadedObjects().isLoaded(referenceOid)) { ObjectAdapter
         * loadedObject = loadedObjects().getLoadedObject(referenceOid);
         * LOG.debug("using loaded object " + loadedObject);
         * object.initAssociation((OneToOneAssociation) field, loadedObject); }
         * else { ObjectAdapter fieldObject; Data fieldData = (Data)
         * dataManager.loadData((SerialOid) referenceOid);
         *
         * if (fieldData != null) { fieldObject = (ObjectAdapter)
         * specFor(fieldData).acquireInstance(); } else { fieldObject =
         * (ObjectAdapter) field.getSpecification().acquireInstance(); }
         *
         * fieldObject.setOid(referenceOid);
         *
         * if (fieldObject instanceof CollectionAdapter) {
         * fieldObject.setResolved(); }
         *
         * loadedObjects().loaded(fieldObject);
         * object.initAssociation((OneToOneAssociation) field, fieldObject); }
         */
    }

    private void initObjectSetupCollection(final ObjectAdapter object, final ObjectData data, final ObjectAssociation field) {
        /*
         * The internal collection is already a part of the object, and
         * therefore cannot be recreated, but its oid must be set
         */
        final ReferenceVector refs = (ReferenceVector) data.get(field.getId());
        final ObjectAdapter collection = field.get(object);
        if (collection.getResolveState().canChangeTo(ResolveState.RESOLVING)) {
            PersistorUtil.start(collection, ResolveState.RESOLVING);
            final int size = refs == null ? 0 : refs.size();
            final ObjectAdapter[] elements = new ObjectAdapter[size];
            for (int j = 0; j < size; j++) {
                final SerialOid elementOid = refs.elementAt(j);
                ObjectAdapter adapter;
                adapter = getAdapterManager().getAdapterFor(elementOid);
                if (adapter == null) {
                    adapter = getObject(elementOid, null);
                }
                elements[j] = adapter;
            }
            final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collection);
            facet.init(collection, elements);
            PersistorUtil.end(collection);
        }
    }

    // /////////////////////////////////////////////////////////
    // Transaction Management
    // /////////////////////////////////////////////////////////

    @Override
    public void startTransaction() {
        LOG.debug("start transaction");
    }

    @Override
    public void endTransaction() {
        LOG.debug("end transaction");
    }

    @Override
    public void abortTransaction() {
        LOG.debug("transaction aborted");
    }

    // /////////////////////////////////////////////////////////
    // createXxxCommands
    // /////////////////////////////////////////////////////////

    @Override
    public CreateObjectCommand createCreateObjectCommand(final ObjectAdapter object) {
        return new XmlCreateObjectCommand(object, dataManager);
    }

    @Override
    public SaveObjectCommand createSaveObjectCommand(final ObjectAdapter object) {
        return new XmlUpdateObjectCommand(object, dataManager);
    }

    @Override
    public DestroyObjectCommand createDestroyObjectCommand(final ObjectAdapter object) {
        return new XmlDestroyObjectCommand(object, dataManager);
    }

    // /////////////////////////////////////////////////////////
    // execute, flush
    // /////////////////////////////////////////////////////////

    @Override
    public void execute(final List<PersistenceCommand> commands) {
        LOG.debug("start execution of transaction");
        for (final PersistenceCommand command : commands) {
            command.execute(null);
        }
        LOG.debug("end execution");
    }

    // /////////////////////////////////////////////////////////
    // getObject, resolveImmediately, resolveField
    // /////////////////////////////////////////////////////////

    @Override
    public ObjectAdapter getObject(final Oid oid, final ObjectSpecification hint) {
        LOG.debug("getObject " + oid);
        final Data data = dataManager.loadData((SerialOid) oid);
        LOG.debug("  data read " + data);

        ObjectAdapter object;

        if (data instanceof ObjectData) {
            object = recreateObject((ObjectData) data);
        } else if (data instanceof CollectionData) {
            throw new IsisException();
        } else {
            throw new ObjectNotFoundException(oid);
        }
        return object;
    }

    @Override
    public void resolveField(final ObjectAdapter object, final ObjectAssociation field) {
        final ObjectAdapter reference = field.get(object);
        resolveImmediately(reference);
    }

    @Override
    public void resolveImmediately(final ObjectAdapter object) {
        final ObjectData data = (ObjectData) dataManager.loadData((SerialOid) object.getOid());
        Assert.assertNotNull("Not able to read in data during resolve", object, data);
        initObject(object, data);
    }

    /*
     * The ObjectData holds all references for internal collections, so the
     * object should haves its internal collection populated by this method.
     */
    private ObjectAdapter recreateObject(final ObjectData data) {
        final SerialOid oid = data.getOid();
        final ObjectSpecification spec = specFor(data);
        final ObjectAdapter object = getPersistenceSession().recreateAdapter(oid, spec);
        initObject(object, data);
        return object;
    }

    // /////////////////////////////////////////////////////////
    // getInstances, allInstances
    // /////////////////////////////////////////////////////////

    @Override
    public ObjectAdapter[] getInstances(final PersistenceQuery persistenceQuery) {

        if (!(persistenceQuery instanceof PersistenceQueryBuiltIn)) {
            throw new IllegalArgumentException(MessageFormat.format("Provided PersistenceQuery not supported; was {0}; " + "the XML object store only supports {1}", persistenceQuery.getClass().getName(), PersistenceQueryBuiltIn.class.getName()));
        }
        final PersistenceQueryBuiltIn builtIn = (PersistenceQueryBuiltIn) persistenceQuery;

        LOG.debug("getInstances of " + builtIn.getSpecification() + " where " + builtIn);
        final ObjectData patternData = new ObjectData(builtIn.getSpecification(), null, null);
        final ObjectAdapter[] instances = getInstances(patternData, builtIn);
        return instances;
    }

    private ObjectAdapter[] getInstances(final ObjectData patternData, final PersistenceQueryBuiltIn persistenceQuery) {
        final ObjectDataVector data = dataManager.getInstances(patternData);
        final ObjectAdapter[] instances = new ObjectAdapter[data.size()];
        int count = 0;

        for (int i = 0; i < data.size(); i++) {
            final ObjectData instanceData = data.element(i);
            LOG.debug("instance data " + instanceData);

            final SerialOid oid = instanceData.getOid();

            final ObjectSpecification spec = specFor(instanceData);
            final ObjectAdapter instance = getPersistenceSession().recreateAdapter(oid, spec);
            LOG.debug("recreated instance " + instance);
            initObject(instance, instanceData);

            if (persistenceQuery == null || persistenceQuery.matches(instance)) {
                instances[count++] = instance;
            }
        }

        final ObjectAdapter[] array = new ObjectAdapter[count];
        System.arraycopy(instances, 0, array, 0, count);
        return array;
    }

    private ObjectSpecification specFor(final Data data) {
        return getSpecificationLoader().loadSpecification(data.getTypeName());
    }

    // /////////////////////////////////////////////////////////
    // services
    // /////////////////////////////////////////////////////////

    @Override
    public Oid getOidForService(final String name) {
        return serviceManager.getOidForService(name);
    }

    @Override
    public void registerService(final String name, final Oid oid) {
        serviceManager.registerService(name, oid);
    }

    // /////////////////////////////////////////////////////////
    // debugging
    // /////////////////////////////////////////////////////////

    @Override
    public void debugData(final DebugBuilder debug) {
        debug.appendTitle("Business Objects");
        debug.appendln(dataManager.getDebugData());
    }

    @Override
    public String debugTitle() {
        return "XML Object Store";
    }

    // /////////////////////////////////////////////////////////
    // Dependencies (injected)
    // /////////////////////////////////////////////////////////

    /**
     * Set the clock used to generate sequence numbers and last changed dates
     * for version objects.
     */
    public void setClock(final Clock clock) {
        FileVersion.setClock(clock);
    }

    // /////////////////////////////////////////////////////////
    // Dependencies (from singleton)
    // /////////////////////////////////////////////////////////

    protected static SpecificationLoader getSpecificationLoader() {
        return IsisContext.getSpecificationLoader();
    }

    private static AdapterManager getAdapterManager() {
        return getPersistenceSession().getAdapterManager();
    }

    protected static PersistenceSession getPersistenceSession() {
        return IsisContext.getPersistenceSession();
    }

}
TOP

Related Classes of org.apache.isis.runtimes.dflt.objectstores.xml.XmlObjectStore

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.