Package org.apache.isis.objectstore.xml

Source Code of org.apache.isis.objectstore.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.objectstore.xml;

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

import com.google.common.collect.Lists;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

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.mgr.AdapterManager;
import org.apache.isis.core.metamodel.adapter.oid.RootOid;
import org.apache.isis.core.metamodel.adapter.oid.RootOidDefault;
import org.apache.isis.core.metamodel.adapter.oid.TypedOid;
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.SpecificationLoaderSpi;
import org.apache.isis.core.metamodel.spec.feature.Contributed;
import org.apache.isis.core.metamodel.spec.feature.ObjectAssociation;
import org.apache.isis.core.metamodel.spec.feature.OneToOneAssociation;
import org.apache.isis.core.runtime.persistence.ObjectNotFoundException;
import org.apache.isis.core.runtime.persistence.ObjectPersistenceException;
import org.apache.isis.core.runtime.persistence.PersistorUtil;
import org.apache.isis.core.runtime.persistence.objectstore.ObjectStoreSpi;
import org.apache.isis.core.runtime.persistence.objectstore.transaction.CreateObjectCommand;
import org.apache.isis.core.runtime.persistence.objectstore.transaction.DestroyObjectCommand;
import org.apache.isis.core.runtime.persistence.objectstore.transaction.PersistenceCommand;
import org.apache.isis.core.runtime.persistence.objectstore.transaction.SaveObjectCommand;
import org.apache.isis.core.runtime.persistence.query.PersistenceQueryBuiltIn;
import org.apache.isis.core.runtime.system.context.IsisContext;
import org.apache.isis.core.runtime.system.persistence.PersistenceQuery;
import org.apache.isis.core.runtime.system.persistence.PersistenceSession;
import org.apache.isis.objectstore.xml.internal.clock.Clock;
import org.apache.isis.objectstore.xml.internal.commands.XmlCreateObjectCommand;
import org.apache.isis.objectstore.xml.internal.commands.XmlDestroyObjectCommand;
import org.apache.isis.objectstore.xml.internal.commands.XmlUpdateObjectCommand;
import org.apache.isis.objectstore.xml.internal.data.CollectionData;
import org.apache.isis.objectstore.xml.internal.data.Data;
import org.apache.isis.objectstore.xml.internal.data.DataManager;
import org.apache.isis.objectstore.xml.internal.data.ListOfRootOid;
import org.apache.isis.objectstore.xml.internal.data.ObjectData;
import org.apache.isis.objectstore.xml.internal.data.ObjectDataVector;
import org.apache.isis.objectstore.xml.internal.data.xml.Utils;
import org.apache.isis.objectstore.xml.internal.data.xml.XmlDataManager;
import org.apache.isis.objectstore.xml.internal.services.ServiceManager;
import org.apache.isis.objectstore.xml.internal.services.xml.XmlServiceManager;
import org.apache.isis.objectstore.xml.internal.version.FileVersion;

public class XmlObjectStore implements ObjectStoreSpi {

    private static final Logger LOG = LoggerFactory.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 = Utils.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(RootOidDefault.create(cls.getSpecId(), "---dummy-value-never-used---"), 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 adapter, final ObjectData data) {
        if (!adapter.canTransitionToResolving()) {
            return;
        }
        try {
            PersistorUtil.startResolving(adapter);
            final List<ObjectAssociation> fields = adapter.getSpecification().getAssociations(Contributed.EXCLUDED);
            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(adapter, value);
                    }
                } else if (field.isOneToManyAssociation()) {
                    initObjectSetupCollection(adapter, data, field);
                } else if (field.isOneToOneAssociation()) {
                    initObjectSetupReference(adapter, data, field);
                }
            }
            adapter.setVersion(data.getVersion());
        } finally {
            PersistorUtil.toEndState(adapter);
        }
    }

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

        final Data fieldData = dataManager.loadData(referencedOid);

        final ObjectAdapter referencedAdapter = getAdapterManager().adapterFor(referencedOid);
        if (fieldData == null) {
            if (!referencedAdapter.isDestroyed()) {
                referencedAdapter.changeState(ResolveState.DESTROYED);
            }
            LOG.warn("No data found for " + referencedOid + " so field '" + field.getName() + "' not set in object '" + object.titleString() + "'");
        }
        ((OneToOneAssociation) field).initAssociation(object, referencedAdapter);

        // REVIEW: what was this commented out code for?
        /*
         * 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 objectAdapter, 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 ListOfRootOid refs = (ListOfRootOid) data.get(field.getId());
       
        final ObjectAdapter collectionAdapter = field.get(objectAdapter);
        if (!collectionAdapter.canTransitionToResolving()) {
            return;
        }
       
        try {
            PersistorUtil.startResolving(collectionAdapter);
            final int size = refs == null ? 0 : refs.size();
            final ObjectAdapter[] elements = new ObjectAdapter[size];
            for (int j = 0; j < size; j++) {
                final RootOid elementOid = refs.elementAt(j);
                ObjectAdapter adapter;
                adapter = getAdapterManager().getAdapterFor(elementOid);
                if (adapter == null) {
                    adapter = loadInstanceAndAdapt(elementOid);
                }
                elements[j] = adapter;
            }
            final CollectionFacet facet = CollectionFacetUtils.getCollectionFacetFromSpec(collectionAdapter);
            facet.init(collectionAdapter, elements);
        } finally {
            PersistorUtil.toEndState(collectionAdapter);
        }
    }

    // /////////////////////////////////////////////////////////
    // 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 loadInstanceAndAdapt(final TypedOid oid) {
        LOG.debug("getObject " + oid);
        final Data data = dataManager.loadData((RootOidDefault) oid);
        LOG.debug("  data read " + data);

        ObjectAdapter object;

        if (data instanceof ObjectData) {
            object = recreateAdapter((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((RootOidDefault) 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 recreateAdapter(final ObjectData data) {
        final RootOid oid = data.getRootOid();
        final ObjectAdapter adapter = getAdapterManager().adapterFor(oid);
        initObject(adapter, data);
        return adapter;
    }

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

    @Override
    public List<ObjectAdapter> loadInstancesAndAdapt(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;

        final ObjectSpecification objSpec = builtIn.getSpecification();
        LOG.debug("getInstances of " + objSpec + " where " + builtIn);
        final RootOid oid = RootOidDefault.create(objSpec.getSpecId(), "dummy");
        final ObjectData patternData = new ObjectData(oid, null);
        return getInstances(patternData, builtIn);
    }

    private List<ObjectAdapter> getInstances(final ObjectData patternData, final PersistenceQueryBuiltIn persistenceQuery) {
        final ObjectDataVector data = dataManager.getInstances(patternData);
        final List<ObjectAdapter> instances = Lists.newArrayList();
       
        for (int i = 0; i < data.size(); i++) {
            final ObjectData instanceData = data.element(i);
            if(LOG.isDebugEnabled()) {
                LOG.debug("instance data " + instanceData);
            }

            final RootOid oid = instanceData.getRootOid();

            final ObjectAdapter adapter = getAdapterManager().adapterFor(oid);
            if(LOG.isDebugEnabled()) {
                LOG.debug("recreated instance " + adapter);
            }
            initObject(adapter, instanceData);

            if (persistenceQuery == null || persistenceQuery.matches(adapter)) {
                instances.add(adapter);
            }
        }
        return instances;
    }

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

    @Override
    public RootOid getOidForService(ObjectSpecification serviceSpec) {
        return serviceManager.getOidForService(serviceSpec.getSpecId());
    }

    @Override
    public void registerService(final RootOid rootOid) {
        serviceManager.registerService(rootOid);
    }

    // /////////////////////////////////////////////////////////
    // 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 SpecificationLoaderSpi getSpecificationLookup() {
        return IsisContext.getSpecificationLoader();
    }

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

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

}
TOP

Related Classes of org.apache.isis.objectstore.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.