/*
* (C) Copyright 2006-2016 Nuxeo SA (http://nuxeo.com/) and others.
*
* Licensed 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.
*
* Contributors:
* Thomas Roger
* Dragos Mihalache
* Florent Guillaume
*/
package org.nuxeo.ecm.core.api.impl;
import static org.nuxeo.ecm.core.schema.types.ComplexTypeImpl.canonicalXPath;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.nuxeo.common.collections.ScopeType;
import org.nuxeo.common.collections.ScopedMap;
import org.nuxeo.common.utils.Path;
import org.nuxeo.ecm.core.api.CoreSession;
import org.nuxeo.ecm.core.api.DataModel;
import org.nuxeo.ecm.core.api.DocumentModel;
import org.nuxeo.ecm.core.api.DocumentRef;
import org.nuxeo.ecm.core.api.Lock;
import org.nuxeo.ecm.core.api.PathRef;
import org.nuxeo.ecm.core.api.PropertyException;
import org.nuxeo.ecm.core.api.VersioningOption;
import org.nuxeo.ecm.core.api.model.DocumentPart;
import org.nuxeo.ecm.core.api.model.Property;
import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
import org.nuxeo.ecm.core.api.model.PropertyVisitor;
import org.nuxeo.ecm.core.api.model.impl.DocumentPartImpl;
import org.nuxeo.ecm.core.api.model.resolver.DocumentPropertyObjectResolverImpl;
import org.nuxeo.ecm.core.api.model.resolver.PropertyObjectResolver;
import org.nuxeo.ecm.core.api.security.ACP;
import org.nuxeo.ecm.core.schema.DocumentType;
import org.nuxeo.ecm.core.schema.SchemaManager;
import org.nuxeo.ecm.core.schema.types.Schema;
import org.nuxeo.runtime.api.Framework;
/**
* A DocumentModel that can have any schema and is not made persistent by itself. A mockup to keep arbitrary schema
* data.
*/
public class SimpleDocumentModel implements DocumentModel {
private static final long serialVersionUID = 1L;
protected final boolean anySchema;
protected final Map<String, DataModel> dataModels = new HashMap<>();
protected Set<String> schemas;
protected final ScopedMap contextData = new ScopedMap();
protected Path path;
protected String type;
public SimpleDocumentModel(List<String> schemas) {
this.schemas = new HashSet<>();
anySchema = false;
SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
for (String schema : schemas) {
Schema s = schemaManager.getSchema(schema);
DocumentPart part = new DocumentPartImpl(s);
dataModels.put(schema, new DataModelImpl(part));
this.schemas.add(schema);
}
}
public SimpleDocumentModel(String... schemas) {
this(Arrays.asList(schemas));
}
public SimpleDocumentModel() {
schemas = new HashSet<>();
anySchema = true;
}
protected DataModel getDataModelInternal(String schema) {
DataModel dm = dataModels.get(schema);
if (dm == null && anySchema) {
SchemaManager schemaManager = Framework.getLocalService(SchemaManager.class);
Schema s = schemaManager.getSchema(schema);
DocumentPart part = new DocumentPartImpl(s);
dm = new DataModelImpl(part);
dataModels.put(schema, dm);
schemas.add(schema);
}
return dm;
}
@Override
public String[] getSchemas() {
Set<String> keys = dataModels.keySet();
return keys.toArray(new String[keys.size()]);
}
@Override
public String[] getDeclaredSchemas() {
return getSchemas();
}
@Override
public Object getProperty(String schemaName, String name) {
DataModel dm = getDataModelInternal(schemaName);
return dm != null ? dm.getData(name) : null;
}
@Override
public Property getPropertyObject(String schema, String name) {
DocumentPart part = getPart(schema);
return part == null ? null : part.get(name);
}
@Override
public void setProperty(String schemaName, String name, Object value) {
if (name.contains(":")) {
name = name.substring(name.indexOf(":"), name.length());
}
getDataModelInternal(schemaName).setData(name, value);
}
@Override
public Map<String, Object> getProperties(String schemaName) {
return getDataModelInternal(schemaName).getMap();
}
@Override
public void setProperties(String schemaName, Map<String, Object> data) {
DataModel dm = getDataModelInternal(schemaName);
dm.setMap(data);
// force dirty for updated properties
for (String field : data.keySet()) {
dm.setDirty(field);
}
}
@Override
public ScopedMap getContextData() {
return contextData;
}
@Override
public Serializable getContextData(ScopeType scope, String key) {
return getContextData(key);
}
@Override
public void putContextData(ScopeType scope, String key, Serializable value) {
putContextData(key, value);
}
@Override
public Serializable getContextData(String key) {
return contextData.get(key);
}
@Override
public void putContextData(String key, Serializable value) {
contextData.put(key, value);
}
@Override
public void copyContextData(DocumentModel otherDocument) {
contextData.putAll(otherDocument.getContextData());
}
@Override
public Property getProperty(String xpath) throws PropertyException {
if (xpath == null) {
throw new PropertyNotFoundException("null", "Invalid null xpath");
}
String cxpath = canonicalXPath(xpath);
if (cxpath.isEmpty()) {
throw new PropertyNotFoundException(xpath, "Schema not specified");
}
String schemaName = DocumentModelImpl.getXPathSchemaName(cxpath, schemas, null);
if (schemaName == null) {
if (cxpath.indexOf(':') != -1) {
throw new PropertyNotFoundException(xpath, "No such schema");
} else {
throw new PropertyNotFoundException(xpath);
}
}
DocumentPart part = getPart(schemaName);
if (part == null) {
throw new PropertyNotFoundException(xpath);
}
// cut prefix
String partPath = cxpath.substring(cxpath.indexOf(':') + 1);
try {
Property property = part.resolvePath(partPath);
// force dirty for updated properties
property.setForceDirty(true);
return property;
} catch (PropertyNotFoundException e) {
throw new PropertyNotFoundException(xpath, e.getDetail());
}
}
@Override
public Serializable getPropertyValue(String xpath) throws PropertyException {
return getProperty(xpath).getValue();
}
@Override
public void setPropertyValue(String xpath, Serializable value) {
getProperty(xpath).setValue(value);
}
@Override
public DocumentType getDocumentType() {
throw new UnsupportedOperationException();
}
@Override
public String getSessionId() {
throw new UnsupportedOperationException();
}
@Override
public CoreSession getCoreSession() {
throw new UnsupportedOperationException();
}
@Override
public void detach(boolean loadAll) {
}
@Override
public void attach(String sid) {
}
@Override
public DocumentRef getRef() {
throw new UnsupportedOperationException();
}
@Override
public DocumentRef getParentRef() {
if (path == null) {
return null;
}
if (!path.isAbsolute()) {
return null;
}
return new PathRef(path.removeLastSegments(1).toString());
}
@Override
public String getId() {
throw new UnsupportedOperationException();
}
@Override
public String getName() {
return path == null ? null : path.lastSegment();
}
@Override
public Long getPos() {
return null;
}
@Override
public String getPathAsString() {
return path == null ? null : path.toString();
}
@Override
public Path getPath() {
return path;
}
@Override
public String getTitle() {
throw new UnsupportedOperationException();
}
@Override
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
@Override
public Set<String> getFacets() {
throw new UnsupportedOperationException();
}
@Override
public Set<String> getDeclaredFacets() {
return getFacets();
}
@Override
@Deprecated
public Collection<DataModel> getDataModelsCollection() {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public Map<String, DataModel> getDataModels() {
return dataModels;
}
@Override
@Deprecated
public DataModel getDataModel(String schema) {
return getDataModelInternal(schema);
}
@Override
public void setPathInfo(String parentPath, String name) {
path = new Path(parentPath == null ? name : parentPath + '/' + name);
}
@Override
public boolean isLocked() {
throw new UnsupportedOperationException();
}
@Override
public Lock setLock() {
throw new UnsupportedOperationException();
}
@Override
public Lock getLockInfo() {
throw new UnsupportedOperationException();
}
@Override
public Lock removeLock() {
throw new UnsupportedOperationException();
}
@Override
public ACP getACP() {
throw new UnsupportedOperationException();
}
@Override
public void setACP(ACP acp, boolean overwrite) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasSchema(String schema) {
throw new UnsupportedOperationException();
}
@Override
public boolean hasFacet(String facet) {
throw new UnsupportedOperationException();
}
@Override
public boolean addFacet(String facet) {
throw new UnsupportedOperationException();
}
@Override
public boolean removeFacet(String facet) {
throw new UnsupportedOperationException();
}
@Override
public boolean isFolder() {
throw new UnsupportedOperationException();
}
@Override
public boolean isVersionable() {
throw new UnsupportedOperationException();
}
@Override
public boolean isDownloadable() {
throw new UnsupportedOperationException();
}
@Override
public boolean isVersion() {
throw new UnsupportedOperationException();
}
@Override
public boolean isProxy() {
throw new UnsupportedOperationException();
}
@Override
public boolean isImmutable() {
throw new UnsupportedOperationException();
}
@Override
public boolean isDirty() {
throw new UnsupportedOperationException();
}
@Override
public void accept(PropertyVisitor visitor, Object arg) {
throw new UnsupportedOperationException();
}
@Override
public <T> T getAdapter(Class<T> itf) {
throw new UnsupportedOperationException();
}
@Override
public <T> T getAdapter(Class<T> itf, boolean refreshCache) {
throw new UnsupportedOperationException();
}
@Override
public String getCurrentLifeCycleState() {
throw new UnsupportedOperationException();
}
@Override
public String getLifeCyclePolicy() {
throw new UnsupportedOperationException();
}
@Override
public boolean followTransition(String transition) {
throw new UnsupportedOperationException();
}
@Override
public Collection<String> getAllowedStateTransitions() {
throw new UnsupportedOperationException();
}
@Override
public void copyContent(DocumentModel sourceDoc) {
throw new UnsupportedOperationException();
}
@Override
public String getRepositoryName() {
throw new UnsupportedOperationException();
}
@Override
public String getCacheKey() {
throw new UnsupportedOperationException();
}
@Override
public String getSourceId() {
throw new UnsupportedOperationException();
}
@Override
public String getVersionLabel() {
throw new UnsupportedOperationException();
}
@Override
public String getCheckinComment() {
throw new UnsupportedOperationException();
}
@Override
public boolean isPrefetched(String xpath) {
return false;
}
@Override
public boolean isPrefetched(String schemaName, String name) {
return false;
}
@Override
public void prefetchCurrentLifecycleState(String lifecycle) {
throw new UnsupportedOperationException();
}
@Override
public void prefetchLifeCyclePolicy(String lifeCyclePolicy) {
throw new UnsupportedOperationException();
}
@Override
public boolean isLifeCycleLoaded() {
return false;
}
@Override
public <T extends Serializable> T getSystemProp(String systemProperty, Class<T> type) {
throw new UnsupportedOperationException();
}
@Override
@Deprecated
public DocumentPart getPart(String schema) {
DataModel dm = getDataModel(schema);
if (dm != null) {
return ((DataModelImpl) dm).getDocumentPart();
}
return null;
}
@Override
@Deprecated
public DocumentPart[] getParts() {
throw new UnsupportedOperationException();
}
@Override
public Collection<Property> getPropertyObjects(String schema) {
DocumentPart part = getPart(schema);
return part == null ? Collections.emptyList() : part.getChildren();
}
@Override
public void reset() {
throw new UnsupportedOperationException();
}
@Override
public void refresh(int refreshFlags, String[] schemas) {
throw new UnsupportedOperationException();
}
@Override
public void refresh() {
throw new UnsupportedOperationException();
}
@Override
public DocumentModel clone() throws CloneNotSupportedException {
throw new UnsupportedOperationException();
}
@Override
public boolean isCheckedOut() {
throw new UnsupportedOperationException();
}
@Override
public void checkOut() {
throw new UnsupportedOperationException();
}
@Override
public DocumentRef checkIn(VersioningOption option, String description) {
throw new UnsupportedOperationException();
}
@Override
public String getVersionSeriesId() {
throw new UnsupportedOperationException();
}
@Override
public boolean isLatestVersion() {
return false;
}
@Override
public boolean isMajorVersion() {
return false;
}
@Override
public boolean isLatestMajorVersion() {
return false;
}
@Override
public boolean isVersionSeriesCheckedOut() {
return true;
}
@Override
public String getChangeToken() {
return null;
}
@Override
public Map<String, String> getBinaryFulltext() {
return null;
}
@Override
public PropertyObjectResolver getObjectResolver(String xpath) {
return DocumentPropertyObjectResolverImpl.create(this, xpath);
}
}