001/*
002 * (C) Copyright 2006-2010 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 *     Thierry Delprat
018 */
019package org.nuxeo.apidoc.repository;
020
021import java.util.ArrayList;
022import java.util.Calendar;
023import java.util.Date;
024import java.util.List;
025
026import org.nuxeo.apidoc.adapters.BaseNuxeoArtifactDocAdapter;
027import org.nuxeo.apidoc.api.BundleGroup;
028import org.nuxeo.apidoc.api.BundleInfo;
029import org.nuxeo.apidoc.api.ComponentInfo;
030import org.nuxeo.apidoc.api.ExtensionInfo;
031import org.nuxeo.apidoc.api.ExtensionPointInfo;
032import org.nuxeo.apidoc.api.OperationInfo;
033import org.nuxeo.apidoc.api.QueryHelper;
034import org.nuxeo.apidoc.api.SeamComponentInfo;
035import org.nuxeo.apidoc.api.ServiceInfo;
036import org.nuxeo.apidoc.documentation.JavaDocHelper;
037import org.nuxeo.apidoc.snapshot.DistributionSnapshot;
038import org.nuxeo.common.utils.Path;
039import org.nuxeo.ecm.core.api.CoreSession;
040import org.nuxeo.ecm.core.api.DocumentModel;
041import org.nuxeo.ecm.core.api.DocumentModelList;
042import org.nuxeo.ecm.core.api.DocumentRef;
043import org.nuxeo.ecm.core.api.PathRef;
044import org.nuxeo.ecm.core.api.PropertyException;
045import org.nuxeo.ecm.core.query.sql.NXQL;
046
047public class RepositoryDistributionSnapshot extends BaseNuxeoArtifactDocAdapter implements DistributionSnapshot {
048
049    protected JavaDocHelper jdocHelper = null;
050
051    public static RepositoryDistributionSnapshot create(DistributionSnapshot distrib, CoreSession session,
052            String containerPath, String label) {
053        DocumentModel doc = session.createDocumentModel(TYPE_NAME);
054        String name = computeDocumentName(distrib.getKey());
055        if (label != null) {
056            name = computeDocumentName(label);
057        }
058        String targetPath = new Path(containerPath).append(name).toString();
059
060        boolean exist = false;
061        if (session.exists(new PathRef(targetPath))) {
062            exist = true;
063            doc = session.getDocument(new PathRef(targetPath));
064        }
065
066        doc.setPathInfo(containerPath, name);
067        if (label == null) {
068            doc.setPropertyValue("dc:title", distrib.getKey());
069            doc.setPropertyValue(PROP_KEY, distrib.getKey());
070            doc.setPropertyValue(PROP_NAME, distrib.getName());
071            doc.setPropertyValue(PROP_VERSION, distrib.getVersion());
072        } else {
073            doc.setPropertyValue("dc:title", label);
074            doc.setPropertyValue(PROP_KEY, label + "-" + distrib.getVersion());
075            doc.setPropertyValue(PROP_NAME, label);
076            doc.setPropertyValue(PROP_VERSION, distrib.getVersion());
077        }
078
079        if (exist) {
080            doc = session.saveDocument(doc);
081        } else {
082            doc = session.createDocument(doc);
083        }
084        return new RepositoryDistributionSnapshot(doc);
085    }
086
087    public static List<DistributionSnapshot> readPersistentSnapshots(CoreSession session) {
088        List<DistributionSnapshot> result = new ArrayList<DistributionSnapshot>();
089        String query = "SELECT * FROM " + TYPE_NAME + " where ecm:currentLifeCycleState != 'deleted'";
090        DocumentModelList docs = session.query(query);
091        for (DocumentModel child : docs) {
092            DistributionSnapshot ob = child.getAdapter(DistributionSnapshot.class);
093            if (ob != null) {
094                result.add(ob);
095            }
096        }
097        return result;
098    }
099
100    public RepositoryDistributionSnapshot(DocumentModel doc) {
101        super(doc);
102    }
103
104    protected <T> List<T> getChildren(Class<T> adapter, String docType) {
105        List<T> result = new ArrayList<T>();
106        String query = QueryHelper.select(docType, doc);
107        DocumentModelList docs = getCoreSession().query(query);
108        for (DocumentModel child : docs) {
109            T ob = child.getAdapter(adapter);
110            if (ob != null) {
111                result.add(ob);
112            }
113        }
114        return result;
115    }
116
117    protected <T> T getChild(Class<T> adapter, String docType, String idField, String id) {
118        String query = QueryHelper.select(docType, doc) + " AND " + idField + " = " + NXQL.escapeString(id);
119        DocumentModelList docs = getCoreSession().query(query);
120        if (docs.isEmpty()) {
121            log.error("Unable to find " + docType + " for id " + id);
122        } else if (docs.size() == 1) {
123            return docs.get(0).getAdapter(adapter);
124        } else {
125            log.error("multiple match for " + docType + " for id " + id);
126            return docs.get(0).getAdapter(adapter);
127        }
128        return null;
129    }
130
131    @Override
132    public BundleInfo getBundle(String id) {
133        return getChild(BundleInfo.class, BundleInfo.TYPE_NAME, BundleInfo.PROP_BUNDLE_ID, id);
134    }
135
136    @Override
137    public BundleGroup getBundleGroup(String groupId) {
138        return getChild(BundleGroup.class, BundleGroup.TYPE_NAME, BundleGroup.PROP_KEY, groupId);
139    }
140
141    protected DocumentModel getBundleContainer() {
142        DocumentRef ref = new PathRef(doc.getPathAsString(), SnapshotPersister.Bundle_Root_NAME);
143        if (getCoreSession().exists(ref)) {
144            return getCoreSession().getDocument(ref);
145        } else {
146            // for compatibility with the previous persistence model
147            return doc;
148        }
149    }
150
151    @Override
152    public List<BundleGroup> getBundleGroups() {
153        List<BundleGroup> grps = new ArrayList<BundleGroup>();
154        String query = QueryHelper.select(BundleGroup.TYPE_NAME, doc, NXQL.ECM_PARENTID, getBundleContainer().getId());
155        DocumentModelList docs = getCoreSession().query(query);
156        for (DocumentModel child : docs) {
157            BundleGroup bg = child.getAdapter(BundleGroup.class);
158            if (bg != null) {
159                grps.add(bg);
160            }
161        }
162        return grps;
163    }
164
165    @Override
166    public List<String> getBundleIds() {
167        List<String> ids = new ArrayList<String>();
168        for (BundleInfo bi : getChildren(BundleInfo.class, BundleInfo.TYPE_NAME)) {
169            ids.add(bi.getId());
170        }
171        return ids;
172    }
173
174    @Override
175    public ComponentInfo getComponent(String id) {
176        return getChild(ComponentInfo.class, ComponentInfo.TYPE_NAME, ComponentInfo.PROP_COMPONENT_ID, id);
177    }
178
179    @Override
180    public List<String> getComponentIds() {
181        List<String> ids = new ArrayList<String>();
182        for (ComponentInfo ci : getChildren(ComponentInfo.class, ComponentInfo.TYPE_NAME)) {
183            ids.add(ci.getId());
184        }
185        return ids;
186    }
187
188    @Override
189    public ExtensionInfo getContribution(String id) {
190        return getChild(ExtensionInfo.class, ExtensionInfo.TYPE_NAME, ExtensionInfo.PROP_CONTRIB_ID, id);
191    }
192
193    @Override
194    public List<String> getContributionIds() {
195        List<String> ids = new ArrayList<String>();
196        for (ExtensionInfo xi : getChildren(ExtensionInfo.class, ExtensionInfo.TYPE_NAME)) {
197            ids.add(xi.getId());
198        }
199        return ids;
200    }
201
202    @Override
203    public List<ExtensionInfo> getContributions() {
204        return getChildren(ExtensionInfo.class, ExtensionInfo.TYPE_NAME);
205    }
206
207    @Override
208    public ExtensionPointInfo getExtensionPoint(String id) {
209        return getChild(ExtensionPointInfo.class, ExtensionPointInfo.TYPE_NAME, ExtensionPointInfo.PROP_EP_ID, id);
210    }
211
212    @Override
213    public List<String> getExtensionPointIds() {
214        List<String> ids = new ArrayList<String>();
215        for (ExtensionPointInfo xpi : getChildren(ExtensionPointInfo.class, ExtensionPointInfo.TYPE_NAME)) {
216            ids.add(xpi.getId());
217        }
218        return ids;
219    }
220
221    @Override
222    public List<String> getBundleGroupChildren(String groupId) {
223        BundleGroup bg = getChild(BundleGroup.class, BundleGroup.TYPE_NAME, BundleGroup.PROP_KEY, groupId);
224        return bg.getBundleIds();
225    }
226
227    public List<String> getBundleGroupIds() {
228        List<String> ids = new ArrayList<String>();
229        for (BundleGroup bg : getChildren(BundleGroup.class, BundleGroup.TYPE_NAME)) {
230            ids.add(bg.getId());
231        }
232        return ids;
233    }
234
235    @Override
236    public List<String> getServiceIds() {
237        List<String> ids = new ArrayList<String>();
238        String query = QueryHelper.select(ComponentInfo.TYPE_NAME, doc);
239        DocumentModelList components = getCoreSession().query(query);
240        for (DocumentModel componentDoc : components) {
241            ComponentInfo ci = componentDoc.getAdapter(ComponentInfo.class);
242            if (ci != null) {
243                ids.addAll(ci.getServiceNames());
244            }
245        }
246        return ids;
247    }
248
249    @Override
250    public String getName() {
251        try {
252            return (String) doc.getPropertyValue(PROP_NAME);
253        } catch (PropertyException e) {
254            log.error("Error while reading nxdistribution:name", e);
255            return "!unknown!";
256        }
257    }
258
259    @Override
260    public String getVersion() {
261        try {
262            return (String) doc.getPropertyValue(PROP_VERSION);
263        } catch (PropertyException e) {
264            log.error("Error while reading nxdistribution:version", e);
265            return "!unknown!";
266        }
267    }
268
269    @Override
270    public String getKey() {
271        try {
272            return (String) doc.getPropertyValue(PROP_KEY);
273        } catch (PropertyException e) {
274            log.error("Error while reading nxdistribution:key", e);
275            return "!unknown!";
276        }
277    }
278
279    @Override
280    public List<Class<?>> getSpi() {
281        return null;
282    }
283
284    @Override
285    public String getId() {
286        return getKey();
287    }
288
289    @Override
290    public String getArtifactType() {
291        return TYPE_NAME;
292    }
293
294    @Override
295    public ServiceInfo getService(String id) {
296        String query = QueryHelper.select(ServiceInfo.TYPE_NAME, getDoc()) + " AND " + ServiceInfo.PROP_CLASS_NAME
297                + " = " + NXQL.escapeString(id);
298        DocumentModelList docs = getCoreSession().query(query);
299        if (docs.size() == 1) {
300            return docs.get(0).getAdapter(ServiceInfo.class);
301        } else {
302            log.error("Multiple services found");
303            return null;
304        }
305    }
306
307    @Override
308    public List<String> getJavaComponentIds() {
309        List<String> ids = new ArrayList<String>();
310        for (ComponentInfo ci : getChildren(ComponentInfo.class, ComponentInfo.TYPE_NAME)) {
311            if (!ci.isXmlPureComponent()) {
312                ids.add(ci.getId());
313            }
314        }
315        return ids;
316    }
317
318    @Override
319    public List<String> getXmlComponentIds() {
320        List<String> ids = new ArrayList<String>();
321        for (ComponentInfo ci : getChildren(ComponentInfo.class, ComponentInfo.TYPE_NAME)) {
322            if (ci.isXmlPureComponent()) {
323                ids.add(ci.getId());
324            }
325        }
326        return ids;
327    }
328
329    @Override
330    public Date getCreationDate() {
331        try {
332            Calendar cal = (Calendar) getDoc().getPropertyValue("dc:created");
333            return cal == null ? null : cal.getTime();
334        } catch (PropertyException e) {
335            return null;
336        }
337    }
338
339    @Override
340    public boolean isLive() {
341        return false;
342    }
343
344    @Override
345    public SeamComponentInfo getSeamComponent(String id) {
346        String name = id.replace("seam:", "");
347        String query = QueryHelper.select(SeamComponentInfo.TYPE_NAME, getDoc()) + " AND "
348                + SeamComponentInfo.PROP_COMPONENT_NAME + " = " + NXQL.escapeString(name);
349        DocumentModelList docs = getCoreSession().query(query);
350        return docs.isEmpty() ? null : docs.get(0).getAdapter(SeamComponentInfo.class);
351    }
352
353    @Override
354    public List<String> getSeamComponentIds() {
355        List<String> result = new ArrayList<String>();
356        String query = QueryHelper.select(SeamComponentInfo.TYPE_NAME, getDoc());
357        DocumentModelList docs = getCoreSession().query(query);
358        for (DocumentModel doc : docs) {
359            result.add(doc.getAdapter(SeamComponentInfo.class).getId());
360        }
361        return result;
362    }
363
364    @Override
365    public List<SeamComponentInfo> getSeamComponents() {
366        List<SeamComponentInfo> result = new ArrayList<SeamComponentInfo>();
367        String query = QueryHelper.select(SeamComponentInfo.TYPE_NAME, getDoc());
368        DocumentModelList docs = getCoreSession().query(query);
369        for (DocumentModel doc : docs) {
370            result.add(doc.getAdapter(SeamComponentInfo.class));
371        }
372        return result;
373    }
374
375    @Override
376    public boolean containsSeamComponents() {
377        return getSeamComponentIds().size() > 0;
378    }
379
380    @Override
381    public OperationInfo getOperation(String id) {
382        if (id.startsWith(OperationInfo.ARTIFACT_PREFIX)) {
383            id = id.substring(OperationInfo.ARTIFACT_PREFIX.length());
384        }
385        String query = QueryHelper.select(OperationInfo.TYPE_NAME, getDoc()) + " AND " + OperationInfo.PROP_NAME + " = "
386                + NXQL.escapeString(id);
387        DocumentModelList docs = getCoreSession().query(query);
388        return docs.isEmpty() ? null : docs.get(0).getAdapter(OperationInfo.class);
389    }
390
391    @Override
392    public List<OperationInfo> getOperations() {
393        List<OperationInfo> result = new ArrayList<OperationInfo>();
394        String query = QueryHelper.select(OperationInfo.TYPE_NAME, getDoc());
395        DocumentModelList docs = getCoreSession().query(query);
396        for (DocumentModel doc : docs) {
397            result.add(doc.getAdapter(OperationInfo.class));
398        }
399        // TODO sort
400        return result;
401    }
402
403    @Override
404    public JavaDocHelper getJavaDocHelper() {
405        if (jdocHelper == null) {
406            jdocHelper = JavaDocHelper.getHelper(getName(), getVersion());
407        }
408        return jdocHelper;
409    }
410
411    @Override
412    public void cleanPreviousArtifacts() {
413        String query = QueryHelper.select("Document", getDoc());
414        List<DocumentRef> refs = new ArrayList<>();
415        DocumentModelList docs = getCoreSession().query(query);
416        for (DocumentModel doc : docs) {
417            refs.add(doc.getRef());
418        }
419        getCoreSession().removeDocuments(refs.toArray(new DocumentRef[refs.size()]));
420    }
421}