001/*
002 * (C) Copyright 2006-2011 Nuxeo SA (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 *     bstefanescu
018 *
019 * $Id$
020 */
021
022package org.nuxeo.ecm.platform.rendering.api;
023
024import java.util.ArrayList;
025import java.util.Arrays;
026import java.util.Calendar;
027import java.util.Collection;
028import java.util.HashMap;
029import java.util.Map;
030
031import org.nuxeo.ecm.core.api.Blob;
032import org.nuxeo.ecm.core.api.Blobs;
033import org.nuxeo.ecm.core.api.CoreSession;
034import org.nuxeo.ecm.core.api.DocumentModel;
035import org.nuxeo.ecm.core.api.PropertyException;
036import org.nuxeo.ecm.core.api.model.PropertyNotFoundException;
037import org.nuxeo.ecm.core.schema.FacetNames;
038import org.nuxeo.ecm.platform.rendering.fm.adapters.SchemaTemplate;
039
040/**
041 * Base class to build views for Document oriented contexts (contexts that are bound to a document).
042 * <p>
043 * Note that this class cannot be used with contexts for which the {@code RenderingContext#getDocument()} method is
044 * returning null.
045 * <p>
046 * This implementation ensure that the context argument is never used so it can be used outside the scope of a rendering
047 * context to get a view over the document.
048 *
049 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a>
050 */
051public class DefaultDocumentView implements DocumentView {
052
053    // Must be returned by get() method when the key is unknown since the caller
054    // should be able to
055    // treat differently a key hit that returned null from a key that is not
056    // known by this view
057    public static final Object UNKNOWN = new Object();
058
059    public interface Field {
060        String getName();
061
062        Object getValue(DocumentModel doc);
063    }
064
065    protected final Map<String, Field> fields;
066
067    public DefaultDocumentView() {
068        fields = new HashMap<>();
069        initialize();
070    }
071
072    public DefaultDocumentView(Map<String, Field> fields) {
073        this.fields = fields == null ? new HashMap<>() : fields;
074    }
075
076    protected void initialize() {
077        addField(SESSION);
078
079        addField(ID);
080        addField(NAME);
081        addField(PATH);
082        addField(TYPE);
083        addField(SID);
084        addField(REPOSITORY);
085
086        addField(SCHEMAS);
087        addField(FACETS);
088        addField(LOCKED);
089        addField(LIFE_CYCLE_STATE);
090        addField(LIFE_CYCLE_POLICY);
091        addField(ALLOWED_STATE_TRANSITIONS);
092        addField(IS_FOLDER);
093        addField(TITLE);
094        addField(AUTHOR);
095        addField(CREATED);
096        addField(MODIFIED);
097        addField(CONTENT);
098
099        addField(PARENT);
100        addField(CHILDREN);
101        addField(REF);
102        addField(VERSIONS);
103        addField(PROXIES);
104        addField(VERSION_LABEL);
105        addField(SOURCE_ID);
106    }
107
108    public final void addField(Field field) {
109        fields.put(field.getName(), field);
110    }
111
112    public final void addFields(Collection<Field> fields) {
113        for (Field field : fields) {
114            this.fields.put(field.getName(), field);
115        }
116    }
117
118    public final void removeField(String name) {
119        fields.remove(name);
120    }
121
122    public Field getField(String name) {
123        return fields.get(name);
124    }
125
126    @Override
127    public Object get(DocumentModel doc, String name) throws PropertyException {
128        Field field = fields.get(name);
129        if (field != null) {
130            return field.getValue(doc);
131        }
132        // may be a a property xpath
133        if (name.indexOf(':') > -1) {
134            return doc.getProperty(name);
135        }
136        // may be a schema name
137        if (doc.hasSchema(name)) {
138            return new SchemaTemplate.DocumentSchema(doc, name);
139        }
140        return UNKNOWN;
141    }
142
143    @Override
144    public Collection<String> keys(DocumentModel doc) {
145        Collection<String> keys = new ArrayList<>(fields.keySet());
146        keys.addAll(Arrays.asList(doc.getSchemas()));
147        return keys;
148    }
149
150    public Map<String, Field> getFields() {
151        return fields;
152    }
153
154    public boolean isEmpty() {
155        return fields.isEmpty();
156    }
157
158    public int size(DocumentModel doc) {
159        return fields.size() + doc.getSchemas().length;
160    }
161
162    protected static final Field SESSION = new Field() {
163        @Override
164        public final String getName() {
165            return "session";
166        }
167
168        @Override
169        public Object getValue(DocumentModel doc) {
170            return doc.getCoreSession();
171        }
172    };
173
174    protected static final Field ID = new Field() {
175        @Override
176        public final String getName() {
177            return "id";
178        }
179
180        @Override
181        public Object getValue(DocumentModel doc) {
182            return doc.getId();
183        }
184    };
185
186    protected static final Field NAME = new Field() {
187        @Override
188        public final String getName() {
189            return "name";
190        }
191
192        @Override
193        public Object getValue(DocumentModel doc) {
194            return doc.getName();
195        }
196    };
197
198    protected static final Field PATH = new Field() {
199        @Override
200        public final String getName() {
201            return "path";
202        }
203
204        @Override
205        public Object getValue(DocumentModel doc) {
206            return doc.getPathAsString();
207        }
208    };
209
210    protected static final Field TYPE = new Field() {
211        @Override
212        public final String getName() {
213            return "type";
214        }
215
216        @Override
217        public Object getValue(DocumentModel doc) {
218            return doc.getType();
219        }
220    };
221
222    protected static final Field SCHEMAS = new Field() {
223        @Override
224        public final String getName() {
225            return "schemas";
226        }
227
228        @Override
229        public Object getValue(DocumentModel doc) {
230            return doc.getSchemas();
231        }
232    };
233
234    protected static final Field FACETS = new Field() {
235        @Override
236        public final String getName() {
237            return "facets";
238        }
239
240        @Override
241        public Object getValue(DocumentModel doc) {
242            return doc.getFacets();
243        }
244    };
245
246    protected static final Field STATE = new Field() {
247        @Override
248        public final String getName() {
249            return "state";
250        }
251
252        @Override
253        public Object getValue(DocumentModel doc) {
254            return doc.getCurrentLifeCycleState();
255        }
256    };
257
258    protected static final Field LOCKED = new Field() {
259        @Override
260        public final String getName() {
261            return "isLocked";
262        }
263
264        @Override
265        public Object getValue(DocumentModel doc) {
266            return doc.isLocked();
267        }
268    };
269
270    protected static final Field LIFE_CYCLE_STATE = new Field() {
271        @Override
272        public final String getName() {
273            return "lifeCycleState";
274        }
275
276        @Override
277        public Object getValue(DocumentModel doc) {
278            return doc.getCurrentLifeCycleState();
279        }
280    };
281
282    protected static final Field LIFE_CYCLE_POLICY = new Field() {
283        @Override
284        public final String getName() {
285            return "lifeCyclePolicy";
286        }
287
288        @Override
289        public Object getValue(DocumentModel doc) {
290            return doc.getLifeCyclePolicy();
291        }
292    };
293
294    protected static final Field ALLOWED_STATE_TRANSITIONS = new Field() {
295        @Override
296        public final String getName() {
297            return "allowedStateTransitions";
298        }
299
300        @Override
301        public Object getValue(DocumentModel doc) {
302            return doc.getAllowedStateTransitions();
303        }
304    };
305
306    protected static final Field IS_FOLDER = new Field() {
307        @Override
308        public final String getName() {
309            return "isFolder";
310        }
311
312        @Override
313        public Object getValue(DocumentModel doc) {
314            return doc.getFacets().contains(FacetNames.FOLDERISH);
315        }
316    };
317
318    protected static final Field TITLE = new Field() {
319        @Override
320        public String getName() {
321            return "title";
322        }
323
324        @Override
325        public Object getValue(DocumentModel doc) {
326            return doc.getTitle();
327        }
328    };
329
330    protected static final Field AUTHOR = new Field() {
331        @Override
332        public String getName() {
333            return "author";
334        }
335
336        @Override
337        public Object getValue(DocumentModel doc) {
338            try {
339                return doc.getPropertyValue("dc:creator");
340            } catch (PropertyNotFoundException e) {
341                // ignore
342            }
343            return null;
344        }
345    };
346
347    protected static final Field CREATED = new Field() {
348        @Override
349        public String getName() {
350            return "created";
351        }
352
353        @Override
354        public Object getValue(DocumentModel doc) {
355            try {
356                Calendar cal = (Calendar) doc.getPropertyValue("dc:created");
357                if (cal != null) {
358                    return cal.getTime();
359                }
360            } catch (PropertyNotFoundException e) {
361                // ignore
362            }
363            return null;
364        }
365    };
366
367    protected static final Field MODIFIED = new Field() {
368        @Override
369        public String getName() {
370            return "modified";
371        }
372
373        @Override
374        public Object getValue(DocumentModel doc) {
375            try {
376                Calendar cal = (Calendar) doc.getPropertyValue("dc:modified");
377                if (cal != null) {
378                    return cal.getTime();
379                }
380            } catch (PropertyNotFoundException e) {
381                // ignore
382            }
383            return null;
384        }
385    };
386
387    protected static final Field CONTENT = new Field() {
388        @Override
389        public String getName() {
390            return "content";
391        }
392
393        @Override
394        public Object getValue(DocumentModel doc) {
395            try {
396                Blob blob = (Blob) doc.getPropertyValue("file:content");
397                if (blob != null) {
398                    return blob;
399                }
400            } catch (PropertyNotFoundException e) {
401                // ignore
402            }
403            return Blobs.createBlob("");
404        }
405    };
406
407    /** @deprecated since 11.1 */
408    @Deprecated
409    protected static final Field SID = new Field() {
410        @Override
411        public String getName() {
412            return "sessionId";
413        }
414
415        @Override
416        public Object getValue(DocumentModel doc) {
417            return "";
418        }
419    };
420
421    protected static final Field REPOSITORY = new Field() {
422        @Override
423        public String getName() {
424            return "repository";
425        }
426
427        @Override
428        public Object getValue(DocumentModel doc) {
429            return doc.getRepositoryName();
430        }
431    };
432
433    protected static final Field PARENT = new Field() {
434        @Override
435        public String getName() {
436            return "parent";
437        }
438
439        @Override
440        public Object getValue(DocumentModel doc) {
441            CoreSession session = doc.getCoreSession();
442            return session.getParentDocument(doc.getRef());
443        }
444    };
445
446    protected static final Field CHILDREN = new Field() {
447        @Override
448        public String getName() {
449            return "children";
450        }
451
452        @Override
453        public Object getValue(DocumentModel doc) {
454            CoreSession session = doc.getCoreSession();
455            return session.getChildren(doc.getRef());
456        }
457    };
458
459    protected static final Field REF = new Field() {
460        @Override
461        public String getName() {
462            return "ref";
463        }
464
465        @Override
466        public Object getValue(DocumentModel doc) {
467            return doc.getRef();
468        }
469    };
470
471    protected static final Field VERSIONS = new Field() {
472        @Override
473        public String getName() {
474            return "versions";
475        }
476
477        @Override
478        public Object getValue(DocumentModel doc) {
479            CoreSession session = doc.getCoreSession();
480            return session.getVersions(doc.getRef());
481        }
482    };
483
484    protected static final Field PROXIES = new Field() {
485        @Override
486        public String getName() {
487            return "proxies";
488        }
489
490        @Override
491        public Object getValue(DocumentModel doc) {
492            CoreSession session = doc.getCoreSession();
493            return session.getProxies(doc.getRef(), null);
494        }
495    };
496
497    protected static final Field VERSION_LABEL = new Field() {
498        @Override
499        public String getName() {
500            return "versionLabel";
501        }
502
503        @Override
504        public Object getValue(DocumentModel doc) {
505            return doc.getVersionLabel();
506        }
507    };
508
509    protected static final Field SOURCE_ID = new Field() {
510        @Override
511        public String getName() {
512            return "sourceId";
513        }
514
515        @Override
516        public Object getValue(DocumentModel doc) {
517            return doc.getSourceId();
518        }
519    };
520
521    /**
522     * The singleton instance that should be used by clients. Warn that this static field must be defined at the end of
523     * the class after any other field class since it will try to register these fields (otherwise fields will not be
524     * defined yet at the time of the initialization of that static member
525     */
526    public static final DefaultDocumentView DEFAULT = new DefaultDocumentView();
527
528}