Package org.apache.chemistry.opencmis.inmemory.storedobj.impl

Source Code of org.apache.chemistry.opencmis.inmemory.storedobj.impl.ObjectStoreImpl

/*
* 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.chemistry.opencmis.inmemory.storedobj.impl;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

import org.apache.chemistry.opencmis.commons.data.Acl;
import org.apache.chemistry.opencmis.commons.data.ContentStream;
import org.apache.chemistry.opencmis.commons.data.PropertyData;
import org.apache.chemistry.opencmis.commons.enums.BaseTypeId;
import org.apache.chemistry.opencmis.commons.enums.IncludeRelationships;
import org.apache.chemistry.opencmis.commons.enums.VersioningState;
import org.apache.chemistry.opencmis.commons.exceptions.CmisConstraintException;
import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Document;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.DocumentVersion;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.Folder;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.MultiFiling;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.ObjectStore;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.SingleFiling;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.StoredObject;
import org.apache.chemistry.opencmis.inmemory.storedobj.api.VersionedDocument;

/**
* The object store is the central core of the in-memory repository. It is based on huge HashMap
* map mapping ids to objects in memory. To allow access from multiple threads a Java concurrent
* HashMap is used that allows parallel access methods.
* <p>
* Certain methods in the in-memory repository must guarantee constraints. For example a folder
* enforces that each child has a unique name. Therefore certain operations must occur in an
* atomic manner. In the example it must be guaranteed that no write access occurs to the
* map between acquiring the iterator to find the children and finishing the add operation when
* no name conflicts can occur. For this purpose this class has methods to lock an unlock the
* state of the repository. It is very important that the caller acquiring the lock enforces an
* unlock under all circumstances. Typical code is:
* <p>
* <pre>
* ObjectStoreImpl os = ... ;
* try {
*     os.lock();
* } finally {
*     os.unlock();
* }
* </pre>
*
* The locking is very coarse-grained. Productive implementations would probably implement finer
* grained locks on a folder or document rather than the complete repository.
*/
public class ObjectStoreImpl implements ObjectStore {

    /**
     * Simple id generator that uses just an integer
     */
    private static int NEXT_UNUSED_ID = 100;

    /**
     * a concurrent HashMap as core element to hold all objects in the repository
     */
    private final Map<String, StoredObject> fStoredObjectMap = new ConcurrentHashMap<String, StoredObject>();

    private final Lock fLock = new ReentrantLock();

    final String fRepositoryId;
    FolderImpl fRootFolder = null;

    public ObjectStoreImpl(String repositoryId) {
        fRepositoryId = repositoryId;
        createRootFolder();
    }

    private static synchronized Integer getNextId() {
        return NEXT_UNUSED_ID++;
    }

    public void lock() {
      fLock.lock();
    }

    public void unlock() {
      fLock.unlock();
    }

    public Folder getRootFolder() {
        return fRootFolder;
    }

    public StoredObject getObjectByPath(String path, String user) {
        for (StoredObject so : fStoredObjectMap.values()) {
            if (so instanceof SingleFiling) {
                String soPath = ((SingleFiling) so).getPath();
                if (soPath.equals(path)) {
                    return so;
                }
            } else if (so instanceof MultiFiling) {
                MultiFiling mfo = (MultiFiling) so;
                List<Folder> parents = mfo.getParents(user);
                for (Folder parent : parents) {
                    String parentPath = parent.getPath();
                    String mfPath = parentPath.equals(Folder.PATH_SEPARATOR) ? parentPath + mfo.getPathSegment()
                            : parentPath + Folder.PATH_SEPARATOR + mfo.getPathSegment();
                    if (mfPath.equals(path)) {
                        return so;
                    }
                }
            } else {
                return null;
            }
        }
        return null;
    }

    public StoredObject getObjectById(String objectId) {
        // we use path as id so we just can look it up in the map
        StoredObject so = fStoredObjectMap.get(objectId);
        return so;
    }

    public void deleteObject(String objectId, Boolean allVersions, String user) {
        String path = objectId; // currently the same
        StoredObject obj = fStoredObjectMap.get(path);

        if (null == obj) {
            throw new RuntimeException("Cannot delete object with id  " + objectId + ". Object does not exist.");
        }

        if (obj instanceof FolderImpl) {
          deleteFolder(objectId, user);
        } else if (obj instanceof DocumentVersion) {
            DocumentVersion vers = (DocumentVersion) obj;
            VersionedDocument parentDoc = vers.getParentDocument();
            fStoredObjectMap.remove(path);
            boolean otherVersionsExist = vers.getParentDocument().deleteVersion(vers);
            if (!otherVersionsExist) {
                fStoredObjectMap.remove(parentDoc.getId());
            }
        } else {
            fStoredObjectMap.remove(path);
        }
    }

    public void removeVersion(DocumentVersion vers) {
        StoredObject found = fStoredObjectMap.remove(vers.getId());

        if (null == found) {
            throw new CmisInvalidArgumentException("Cannot delete object with id  " + vers.getId() + ". Object does not exist.");
        }
    }

    public String storeObject(StoredObject so) {
        String id = so.getId();
        // check if update or create
        if (null == id) {
            id = getNextId().toString();
        }
        fStoredObjectMap.put(id, so);
        return id;
    }

    StoredObject getObject(String id) {
        return fStoredObjectMap.get(id);
    }

    void removeObject(String id) {
        fStoredObjectMap.remove(id);
    }

    public Set<String> getIds() {
        Set<String> entries = fStoredObjectMap.keySet();
        return entries;
    }

    /**
     * Clear repository and remove all data.
     */
    public void clear() {
        lock();
        fStoredObjectMap.clear();
        storeObject(fRootFolder);
        unlock();
    }

    public long getObjectCount() {
        return fStoredObjectMap.size();
    }

    // /////////////////////////////////////////
    // private helper methods

    private void createRootFolder() {
        FolderImpl rootFolder = new FolderImpl(this);
        rootFolder.setName("RootFolder");
        rootFolder.setParent(null);
        rootFolder.setTypeId(BaseTypeId.CMIS_FOLDER.value());
        rootFolder.setCreatedBy("Admin");
        rootFolder.setModifiedBy("Admin");
        rootFolder.setModifiedAtNow();
        rootFolder.setRepositoryId(fRepositoryId);
        rootFolder.persist();
        fRootFolder = rootFolder;
    }

    public Document createDocument(String name,
      Map<String, PropertyData<?>> propMap, String user, Folder folder,
      Acl addACEs, Acl removeACEs)  {
      DocumentImpl doc = new DocumentImpl(this);
        doc.createSystemBasePropertiesWhenCreated(propMap, user);
        doc.setCustomProperties(propMap);
        doc.setRepositoryId(fRepositoryId);
        doc.setName(name);
        if (null != folder) {
            ((FolderImpl)folder).addChildDocument(doc); // add document to folder and
        }
        return doc;
    }

    public DocumentVersion createVersionedDocument(String name,
        Map<String, PropertyData<?>> propMap, String user, Folder folder,
      Acl addACEs, Acl removeACEs, ContentStream contentStream, VersioningState versioningState) {
      VersionedDocumentImpl doc = new VersionedDocumentImpl(this);
        doc.createSystemBasePropertiesWhenCreated(propMap, user);
        doc.setCustomProperties(propMap);
        doc.setRepositoryId(fRepositoryId);
        doc.setName(name);
        DocumentVersion version = doc.addVersion(contentStream, versioningState, user);
        if (null != folder) {
          ((FolderImpl)folder).addChildDocument(doc); // add document to folder and set
        }
        version.createSystemBasePropertiesWhenCreated(propMap, user);
        version.setCustomProperties(propMap);
        doc.persist();
        return version;
    }

    public Folder createFolder(String name,
      Map<String, PropertyData<?>> propMap, String user, Folder parent,
      Acl addACEs, Acl removeACEs) {
     
      FolderImpl folder = new FolderImpl(this, name, null);
        if (null != propMap) {
          folder.createSystemBasePropertiesWhenCreated(propMap, user);
          folder.setCustomProperties(propMap);
        }
        folder.setRepositoryId(fRepositoryId);
        if (null != parent) {
          ((FolderImpl)parent).addChildFolder(folder); // add document to folder and set
        }
        return folder;
    }

    public Folder createFolder(String name) {
      Folder folder = new FolderImpl(this, name, null);
        folder.setRepositoryId(fRepositoryId);
        return folder;
  }
   
  public List<StoredObject> getCheckedOutDocuments(String orderBy,
      String user, IncludeRelationships includeRelationships) {
      List<StoredObject> res = new ArrayList<StoredObject>();

        for (StoredObject so : fStoredObjectMap.values()) {
            if (so instanceof VersionedDocument) {
                VersionedDocument verDoc = (VersionedDocument) so;
                if (verDoc.isCheckedOut()) {
                    res.add(verDoc);
                }
            }
        }

        return res;
    }

    private void deleteFolder(String folderId, String user) {
        StoredObject folder = fStoredObjectMap.get(folderId);
        if (folder == null) {
            throw new CmisInvalidArgumentException("Unknown object with id:  " + folderId);
        }

        if (!(folder instanceof FolderImpl)) {
            throw new CmisInvalidArgumentException("Cannot delete folder with id:  " + folderId
                    + ". Object exists but is not a folder.");
        }

        // check if children exist
        List<StoredObject> children = ((Folder) folder).getChildren(-1, -1, user);
        if (children != null && !children.isEmpty()) {
            throw new CmisConstraintException("Cannot delete folder with id:  " + folderId + ". Folder is not empty.");
        }

        fStoredObjectMap.remove(folderId);
    }

  public StoredObject createRelationship(StoredObject sourceObject,
      StoredObject targetObject, Map<String, PropertyData<?>> propMap,
      String user, Acl addACEs, Acl removeACEs) {
    // TODO Auto-generated method stub
    return null;
  }

}
TOP

Related Classes of org.apache.chemistry.opencmis.inmemory.storedobj.impl.ObjectStoreImpl

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.