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