001/*
002 * (C) Copyright 2006-2018 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Thomas Roger
018 *     Dragos Mihalache
019 *     Florent Guillaume
020 */
021package org.nuxeo.ecm.core.api.impl;
022
023import static org.nuxeo.ecm.core.schema.types.ComplexTypeImpl.canonicalXPath;
024
025import java.io.Serializable;
026import java.util.Arrays;
027import java.util.Collection;
028import java.util.Collections;
029import java.util.HashMap;
030import java.util.HashSet;
031import java.util.List;
032import java.util.Map;
033import java.util.Set;
034
035import org.nuxeo.common.utils.Path;
036import org.nuxeo.ecm.core.api.CoreSession;
037import org.nuxeo.ecm.core.api.DataModel;
038import org.nuxeo.ecm.core.api.DocumentModel;
039import org.nuxeo.ecm.core.api.DocumentRef;
040import org.nuxeo.ecm.core.api.LifeCycleConstants;
041import org.nuxeo.ecm.core.api.Lock;
042import org.nuxeo.ecm.core.api.PathRef;
043import org.nuxeo.ecm.core.api.PropertyException;
044import org.nuxeo.ecm.core.api.VersioningOption;
045import org.nuxeo.ecm.core.api.model.DocumentPart;
046import org.nuxeo.ecm.core.api.model.Property;
047import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
048import org.nuxeo.ecm.core.api.model.PropertyVisitor;
049import org.nuxeo.ecm.core.api.model.impl.DocumentPartImpl;
050import org.nuxeo.ecm.core.api.model.resolver.DocumentPropertyObjectResolverImpl;
051import org.nuxeo.ecm.core.api.model.resolver.PropertyObjectResolver;
052import org.nuxeo.ecm.core.api.security.ACP;
053import org.nuxeo.ecm.core.schema.DocumentType;
054import org.nuxeo.ecm.core.schema.SchemaManager;
055import org.nuxeo.ecm.core.schema.types.Schema;
056import org.nuxeo.runtime.api.Framework;
057
058/**
059 * A DocumentModel that can have any schema and is not made persistent by itself. A mockup to keep arbitrary schema
060 * data.
061 */
062public class SimpleDocumentModel implements DocumentModel {
063
064    private static final long serialVersionUID = 1L;
065
066    protected final boolean anySchema;
067
068    protected final Map<String, DataModel> dataModels = new HashMap<>();
069
070    protected Set<String> schemas;
071
072    protected final Map<String, Serializable> contextData = new HashMap<>();
073
074    protected Path path;
075
076    protected String type;
077
078    public SimpleDocumentModel(List<String> schemas) {
079        this.schemas = new HashSet<>();
080        anySchema = false;
081        SchemaManager schemaManager = Framework.getService(SchemaManager.class);
082        for (String schema : schemas) {
083            Schema s = schemaManager.getSchema(schema);
084            DocumentPart part = new DocumentPartImpl(s);
085            dataModels.put(schema, new DataModelImpl(part));
086            this.schemas.add(schema);
087        }
088    }
089
090    public SimpleDocumentModel(String... schemas) {
091        this(Arrays.asList(schemas));
092    }
093
094    public SimpleDocumentModel() {
095        schemas = new HashSet<>();
096        anySchema = true;
097    }
098
099    protected DataModel getDataModelInternal(String schema) {
100        DataModel dm = dataModels.get(schema);
101        if (dm == null && anySchema) {
102            SchemaManager schemaManager = Framework.getService(SchemaManager.class);
103            Schema s = schemaManager.getSchema(schema);
104            DocumentPart part = new DocumentPartImpl(s);
105            dm = new DataModelImpl(part);
106            dataModels.put(schema, dm);
107            schemas.add(schema);
108        }
109        return dm;
110    }
111
112    @Override
113    public String[] getSchemas() {
114        Set<String> keys = dataModels.keySet();
115        return keys.toArray(new String[keys.size()]);
116    }
117
118    @Override
119    public Object getProperty(String schemaName, String name) {
120        DataModel dm = getDataModelInternal(schemaName);
121        return dm != null ? dm.getData(name) : null;
122    }
123
124    @Override
125    public Property getPropertyObject(String schema, String name) {
126        DocumentPart part = getPart(schema);
127        return part == null ? null : part.get(name);
128    }
129
130    @Override
131    public void setProperty(String schemaName, String name, Object value) {
132        if (name.contains(":")) {
133            name = name.substring(name.indexOf(":"), name.length());
134        }
135        getDataModelInternal(schemaName).setData(name, value);
136    }
137
138    @Override
139    public Map<String, Object> getProperties(String schemaName) {
140        return getDataModelInternal(schemaName).getMap();
141    }
142
143    @Override
144    public void setProperties(String schemaName, Map<String, Object> data) {
145        DataModel dm = getDataModelInternal(schemaName);
146        dm.setMap(data);
147        // force dirty for updated properties
148        for (String field : data.keySet()) {
149            dm.setDirty(field);
150        }
151    }
152
153    @Override
154    public Map<String, Serializable> getContextData() {
155        return contextData;
156    }
157
158    @Override
159    public Serializable getContextData(String key) {
160        return contextData.get(key);
161    }
162
163    @Override
164    public void putContextData(String key, Serializable value) {
165        contextData.put(key, value);
166    }
167
168    @Override
169    public void copyContextData(DocumentModel otherDocument) {
170        contextData.putAll(otherDocument.getContextData());
171    }
172
173    @Override
174    public Property getProperty(String xpath) throws PropertyException {
175        if (xpath == null) {
176            throw new PropertyNotFoundException("null", "Invalid null xpath");
177        }
178        String cxpath = canonicalXPath(xpath);
179        if (cxpath.isEmpty()) {
180            throw new PropertyNotFoundException(xpath, "Schema not specified");
181        }
182        String schemaName = DocumentModelImpl.getXPathSchemaName(cxpath, schemas, null);
183        if (schemaName == null) {
184            if (cxpath.indexOf(':') != -1) {
185                throw new PropertyNotFoundException(xpath, "No such schema");
186            } else {
187                throw new PropertyNotFoundException(xpath);
188            }
189
190        }
191        DocumentPart part = getPart(schemaName);
192        if (part == null) {
193            throw new PropertyNotFoundException(xpath);
194        }
195        // cut prefix
196        String partPath = cxpath.substring(cxpath.indexOf(':') + 1);
197        try {
198            Property property = part.resolvePath(partPath);
199            // force dirty for updated properties
200            property.setForceDirty(true);
201            return property;
202        } catch (PropertyNotFoundException e) {
203            throw new PropertyNotFoundException(xpath, e.getDetail());
204        }
205    }
206
207    @Override
208    public Serializable getPropertyValue(String xpath) throws PropertyException {
209        return getProperty(xpath).getValue();
210    }
211
212    @Override
213    public void setPropertyValue(String xpath, Serializable value) {
214        getProperty(xpath).setValue(value);
215    }
216
217    @Override
218    public DocumentType getDocumentType() {
219        throw new UnsupportedOperationException();
220    }
221
222    @Override
223    public String getSessionId() {
224        throw new UnsupportedOperationException();
225    }
226
227    @Override
228    public CoreSession getCoreSession() {
229        throw new UnsupportedOperationException();
230    }
231
232    @Override
233    public void detach(boolean loadAll) {
234    }
235
236    @Override
237    public void attach(String sid) {
238    }
239
240    @Override
241    public DocumentRef getRef() {
242        throw new UnsupportedOperationException();
243    }
244
245    @Override
246    public DocumentRef getParentRef() {
247        if (path == null) {
248            return null;
249        }
250        if (!path.isAbsolute()) {
251            return null;
252        }
253        return new PathRef(path.removeLastSegments(1).toString());
254    }
255
256    @Override
257    public String getId() {
258        throw new UnsupportedOperationException();
259    }
260
261    @Override
262    public String getName() {
263        return path == null ? null : path.lastSegment();
264    }
265
266    @Override
267    public Long getPos() {
268        return null;
269    }
270
271    @Override
272    public String getPathAsString() {
273        return path == null ? null : path.toString();
274    }
275
276    @Override
277    public Path getPath() {
278        return path;
279    }
280
281    @Override
282    public String getTitle() {
283        throw new UnsupportedOperationException();
284    }
285
286    @Override
287    public String getType() {
288        return type;
289    }
290
291    public void setType(String type) {
292        this.type = type;
293    }
294
295    @Override
296    public Set<String> getFacets() {
297        throw new UnsupportedOperationException();
298    }
299
300    @Override
301    @Deprecated
302    public Collection<DataModel> getDataModelsCollection() {
303        throw new UnsupportedOperationException();
304    }
305
306    @Override
307    @Deprecated
308    public Map<String, DataModel> getDataModels() {
309        return dataModels;
310    }
311
312    @Override
313    @Deprecated
314    public DataModel getDataModel(String schema) {
315        return getDataModelInternal(schema);
316    }
317
318    @Override
319    public void setPathInfo(String parentPath, String name) {
320        path = new Path(parentPath == null ? name : parentPath + '/' + name);
321    }
322
323    @Override
324    public boolean isLocked() {
325        throw new UnsupportedOperationException();
326    }
327
328    @Override
329    public Lock setLock() {
330        throw new UnsupportedOperationException();
331    }
332
333    @Override
334    public Lock getLockInfo() {
335        throw new UnsupportedOperationException();
336    }
337
338    @Override
339    public Lock removeLock() {
340        throw new UnsupportedOperationException();
341    }
342
343    @Override
344    public ACP getACP() {
345        throw new UnsupportedOperationException();
346    }
347
348    @Override
349    public void setACP(ACP acp, boolean overwrite) {
350        throw new UnsupportedOperationException();
351    }
352
353    @Override
354    public boolean hasSchema(String schema) {
355        throw new UnsupportedOperationException();
356    }
357
358    @Override
359    public boolean hasFacet(String facet) {
360        throw new UnsupportedOperationException();
361    }
362
363    @Override
364    public boolean addFacet(String facet) {
365        throw new UnsupportedOperationException();
366    }
367
368    @Override
369    public boolean removeFacet(String facet) {
370        throw new UnsupportedOperationException();
371    }
372
373    @Override
374    public boolean isTrashed() {
375        return LifeCycleConstants.DELETED_STATE.equals(getCurrentLifeCycleState());
376    }
377
378    @Override
379    public boolean isFolder() {
380        throw new UnsupportedOperationException();
381    }
382
383    @Override
384    public boolean isVersionable() {
385        throw new UnsupportedOperationException();
386    }
387
388    @Override
389    public boolean isDownloadable() {
390        throw new UnsupportedOperationException();
391    }
392
393    @Override
394    public boolean isVersion() {
395        throw new UnsupportedOperationException();
396    }
397
398    @Override
399    public boolean isProxy() {
400        throw new UnsupportedOperationException();
401    }
402
403    @Override
404    public boolean isImmutable() {
405        throw new UnsupportedOperationException();
406    }
407
408    @Override
409    public boolean isDirty() {
410        throw new UnsupportedOperationException();
411    }
412
413    @Override
414    public void accept(PropertyVisitor visitor, Object arg) {
415        throw new UnsupportedOperationException();
416    }
417
418    @Override
419    public <T> T getAdapter(Class<T> itf) {
420        throw new UnsupportedOperationException();
421    }
422
423    @Override
424    public <T> T getAdapter(Class<T> itf, boolean refreshCache) {
425        throw new UnsupportedOperationException();
426    }
427
428    @Override
429    public String getCurrentLifeCycleState() {
430        throw new UnsupportedOperationException();
431    }
432
433    @Override
434    public String getLifeCyclePolicy() {
435        throw new UnsupportedOperationException();
436    }
437
438    @Override
439    public boolean followTransition(String transition) {
440        throw new UnsupportedOperationException();
441    }
442
443    @Override
444    public Collection<String> getAllowedStateTransitions() {
445        throw new UnsupportedOperationException();
446    }
447
448    @Override
449    public void copyContent(DocumentModel sourceDoc) {
450        throw new UnsupportedOperationException();
451    }
452
453    @Override
454    public String getRepositoryName() {
455        throw new UnsupportedOperationException();
456    }
457
458    @Override
459    public String getCacheKey() {
460        throw new UnsupportedOperationException();
461    }
462
463    @Override
464    public String getSourceId() {
465        throw new UnsupportedOperationException();
466    }
467
468    @Override
469    public String getVersionLabel() {
470        throw new UnsupportedOperationException();
471    }
472
473    @Override
474    public String getCheckinComment() {
475        throw new UnsupportedOperationException();
476    }
477
478    @Override
479    public boolean isPrefetched(String xpath) {
480        return false;
481    }
482
483    @Override
484    public boolean isPrefetched(String schemaName, String name) {
485        return false;
486    }
487
488    @Override
489    public void prefetchCurrentLifecycleState(String lifecycle) {
490        throw new UnsupportedOperationException();
491    }
492
493    @Override
494    public void prefetchLifeCyclePolicy(String lifeCyclePolicy) {
495        throw new UnsupportedOperationException();
496    }
497
498    @Override
499    public boolean isLifeCycleLoaded() {
500        throw new UnsupportedOperationException();
501    }
502
503    @Override
504    public <T extends Serializable> T getSystemProp(String systemProperty, Class<T> type) {
505        throw new UnsupportedOperationException();
506    }
507
508    @Override
509    @Deprecated
510    public DocumentPart getPart(String schema) {
511        DataModel dm = getDataModel(schema);
512        if (dm != null) {
513            return ((DataModelImpl) dm).getDocumentPart();
514        }
515        return null;
516    }
517
518    @Override
519    @Deprecated
520    public DocumentPart[] getParts() {
521        throw new UnsupportedOperationException();
522    }
523
524    @Override
525    public Collection<Property> getPropertyObjects(String schema) {
526        DocumentPart part = getPart(schema);
527        return part == null ? Collections.emptyList() : part.getChildren();
528    }
529
530    @Override
531    public void reset() {
532        throw new UnsupportedOperationException();
533    }
534
535    @Override
536    public void refresh(int refreshFlags, String[] schemas) {
537        throw new UnsupportedOperationException();
538    }
539
540    @Override
541    public void refresh() {
542        throw new UnsupportedOperationException();
543    }
544
545    @Override
546    public DocumentModel clone() throws CloneNotSupportedException {
547        throw new UnsupportedOperationException();
548    }
549
550    @Override
551    public boolean isCheckedOut() {
552        throw new UnsupportedOperationException();
553    }
554
555    @Override
556    public void checkOut() {
557        throw new UnsupportedOperationException();
558    }
559
560    @Override
561    public DocumentRef checkIn(VersioningOption option, String description) {
562        throw new UnsupportedOperationException();
563    }
564
565    @Override
566    public String getVersionSeriesId() {
567        throw new UnsupportedOperationException();
568    }
569
570    @Override
571    public boolean isLatestVersion() {
572        return false;
573    }
574
575    @Override
576    public boolean isMajorVersion() {
577        return false;
578    }
579
580    @Override
581    public boolean isLatestMajorVersion() {
582        return false;
583    }
584
585    @Override
586    public boolean isVersionSeriesCheckedOut() {
587        return true;
588    }
589
590    @Override
591    public String getChangeToken() {
592        return null;
593    }
594
595    @Override
596    public Map<String, String> getBinaryFulltext() {
597        return null;
598    }
599
600    @Override
601    public PropertyObjectResolver getObjectResolver(String xpath) {
602        return DocumentPropertyObjectResolverImpl.create(this, xpath);
603    }
604
605}