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.browse;
018
019import java.io.IOException;
020import java.io.Reader;
021import java.io.StringReader;
022import java.io.StringWriter;
023import java.net.URI;
024import java.net.URISyntaxException;
025import java.util.ArrayList;
026import java.util.Collections;
027import java.util.HashMap;
028import java.util.List;
029import java.util.Map;
030
031import javax.ws.rs.GET;
032import javax.ws.rs.Path;
033import javax.ws.rs.PathParam;
034import javax.ws.rs.Produces;
035import javax.ws.rs.QueryParam;
036import javax.ws.rs.core.Response;
037
038import org.json.JSONArray;
039import org.json.JSONException;
040import org.json.JSONObject;
041import org.nuxeo.apidoc.api.BundleGroup;
042import org.nuxeo.apidoc.api.BundleGroupFlatTree;
043import org.nuxeo.apidoc.api.BundleGroupTreeHelper;
044import org.nuxeo.apidoc.api.BundleInfo;
045import org.nuxeo.apidoc.api.ComponentInfo;
046import org.nuxeo.apidoc.api.DocumentationItem;
047import org.nuxeo.apidoc.api.ExtensionInfo;
048import org.nuxeo.apidoc.api.ExtensionPointInfo;
049import org.nuxeo.apidoc.api.NuxeoArtifact;
050import org.nuxeo.apidoc.api.OperationInfo;
051import org.nuxeo.apidoc.api.SeamComponentInfo;
052import org.nuxeo.apidoc.api.ServiceInfo;
053import org.nuxeo.apidoc.documentation.DocumentationService;
054import org.nuxeo.apidoc.search.ArtifactSearcher;
055import org.nuxeo.apidoc.snapshot.DistributionSnapshot;
056import org.nuxeo.apidoc.snapshot.SnapshotManager;
057import org.nuxeo.apidoc.tree.TreeHelper;
058import org.nuxeo.ecm.automation.OperationException;
059import org.nuxeo.ecm.core.api.NuxeoException;
060import org.nuxeo.ecm.platform.rendering.wiki.WikiSerializer;
061import org.nuxeo.ecm.webengine.model.Resource;
062import org.nuxeo.ecm.webengine.model.WebObject;
063import org.nuxeo.ecm.webengine.model.exceptions.WebResourceNotFoundException;
064import org.nuxeo.ecm.webengine.model.impl.DefaultObject;
065import org.nuxeo.runtime.api.Framework;
066import org.wikimodel.wem.WikiParserException;
067
068@WebObject(type = "apibrowser")
069public class ApiBrowser extends DefaultObject {
070
071    protected String distributionId;
072
073    protected boolean embeddedMode = false;
074
075    protected SnapshotManager getSnapshotManager() {
076        return Framework.getLocalService(SnapshotManager.class);
077    }
078
079    protected ArtifactSearcher getSearcher() {
080        return Framework.getLocalService(ArtifactSearcher.class);
081    }
082
083    @Override
084    protected void initialize(Object... args) {
085        distributionId = (String) args[0];
086        if (args.length > 1) {
087            Boolean embed = (Boolean) args[1];
088            embeddedMode = embed == null ? false : embed.booleanValue();
089        }
090    }
091
092    @GET
093    @Produces("text/plain")
094    @Path("tree")
095    public Object tree(@QueryParam("root") String source) {
096        return TreeHelper.updateTree(getContext(), source);
097    }
098
099    @GET
100    @Produces("text/html")
101    @Path("treeView")
102    public Object treeView() {
103        return getView("tree").arg(Distribution.DIST_ID, ctx.getProperty(Distribution.DIST_ID));
104    }
105
106    @GET
107    @Produces("text/html")
108    public Object doGet() {
109        if (embeddedMode) {
110            DistributionSnapshot snap = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession());
111            Map<String, Integer> stats = new HashMap<String, Integer>();
112            stats.put("bundles", Integer.valueOf(snap.getBundleIds().size()));
113            stats.put("jComponents", Integer.valueOf(snap.getJavaComponentIds().size()));
114            stats.put("xComponents", Integer.valueOf(snap.getXmlComponentIds().size()));
115            stats.put("services", Integer.valueOf(snap.getServiceIds().size()));
116            stats.put("xps", Integer.valueOf(snap.getExtensionPointIds().size()));
117            stats.put("contribs", Integer.valueOf(snap.getComponentIds().size()));
118            return getView("indexSimple").arg(Distribution.DIST_ID, ctx.getProperty(Distribution.DIST_ID)).arg("stats",
119                    stats);
120        } else {
121            return getView("index").arg(Distribution.DIST_ID, ctx.getProperty(Distribution.DIST_ID));
122        }
123    }
124
125    @GET
126    @Produces("text/html")
127    @Path("listBundleGroups")
128    public Object getMavenGroups() {
129        BundleGroupTreeHelper bgth = new BundleGroupTreeHelper(getSnapshotManager().getSnapshot(distributionId,
130                ctx.getCoreSession()));
131        List<BundleGroupFlatTree> tree = bgth.getBundleGroupTree();
132        return getView("listBundleGroups").arg("tree", tree).arg(Distribution.DIST_ID,
133                ctx.getProperty(Distribution.DIST_ID));
134    }
135
136    public Map<String, DocumentationItem> getDescriptions(String targetType) {
137        DocumentationService ds = Framework.getLocalService(DocumentationService.class);
138        return ds.getAvailableDescriptions(getContext().getCoreSession(), targetType);
139    }
140
141    @GET
142    @Produces("text/html")
143    @Path("listBundles")
144    public Object getBundles() {
145        List<String> bundleIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getBundleIds();
146        return getView("listBundles").arg("bundleIds", bundleIds).arg(Distribution.DIST_ID,
147                ctx.getProperty(Distribution.DIST_ID));
148    }
149
150    @GET
151    @Produces("text/html")
152    @Path("filterBundles")
153    public Object filterBundles() {
154        String fulltext = getContext().getForm().getFormProperty("fulltext");
155        List<NuxeoArtifact> artifacts = getSearcher().filterArtifact(getContext().getCoreSession(), distributionId,
156                BundleInfo.TYPE_NAME, fulltext);
157        List<String> bundleIds = new ArrayList<String>();
158        for (NuxeoArtifact item : artifacts) {
159            bundleIds.add(item.getId());
160        }
161        return getView("listBundles").arg("bundleIds", bundleIds).arg(Distribution.DIST_ID,
162                ctx.getProperty(Distribution.DIST_ID)).arg("searchFilter", fulltext);
163    }
164
165    @GET
166    @Produces("text/html")
167    @Path("listComponents")
168    public Object getComponents() {
169        List<String> javaComponentIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getJavaComponentIds();
170        List<ArtifactLabel> javaLabels = new ArrayList<ArtifactLabel>();
171        for (String id : javaComponentIds) {
172            javaLabels.add(ArtifactLabel.createLabelFromComponent(id));
173        }
174
175        List<String> xmlComponentIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getXmlComponentIds();
176        List<ArtifactLabel> xmlLabels = new ArrayList<ArtifactLabel>();
177        for (String id : xmlComponentIds) {
178            xmlLabels.add(ArtifactLabel.createLabelFromComponent(id));
179        }
180
181        Collections.sort(javaLabels);
182        Collections.sort(xmlLabels);
183
184        return getView("listComponents").arg("javaComponents", javaLabels).arg("xmlComponents", xmlLabels).arg(
185                Distribution.DIST_ID, ctx.getProperty(Distribution.DIST_ID));
186    }
187
188    @GET
189    @Produces("text/html")
190    @Path("filterComponents")
191    public Object filterComponents() {
192        String fulltext = getContext().getForm().getFormProperty("fulltext");
193        List<NuxeoArtifact> artifacts = getSearcher().filterArtifact(getContext().getCoreSession(), distributionId,
194                ComponentInfo.TYPE_NAME, fulltext);
195
196        List<ArtifactLabel> xmlLabels = new ArrayList<ArtifactLabel>();
197        List<ArtifactLabel> javaLabels = new ArrayList<ArtifactLabel>();
198
199        for (NuxeoArtifact item : artifacts) {
200            ComponentInfo ci = (ComponentInfo) item;
201            if (ci.isXmlPureComponent()) {
202                xmlLabels.add(ArtifactLabel.createLabelFromComponent(ci.getId()));
203            } else {
204                javaLabels.add(ArtifactLabel.createLabelFromComponent(ci.getId()));
205            }
206        }
207        return getView("listComponents").arg("javaComponents", javaLabels).arg("xmlComponents", xmlLabels).arg(
208                Distribution.DIST_ID, ctx.getProperty(Distribution.DIST_ID)).arg("searchFilter", fulltext);
209    }
210
211    @GET
212    @Produces("text/html")
213    @Path("listServices")
214    public Object getServices() {
215        List<String> serviceIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getServiceIds();
216
217        List<ArtifactLabel> serviceLabels = new ArrayList<ArtifactLabel>();
218
219        for (String id : serviceIds) {
220            serviceLabels.add(ArtifactLabel.createLabelFromService(id));
221        }
222        Collections.sort(serviceLabels);
223
224        return getView("listServices").arg("services", serviceLabels).arg(Distribution.DIST_ID,
225                ctx.getProperty(Distribution.DIST_ID));
226    }
227
228    protected Map<String, String> getRenderedDescriptions(String type) {
229
230        Map<String, DocumentationItem> descs = getDescriptions(type);
231        Map<String, String> result = new HashMap<String, String>();
232
233        for (String key : descs.keySet()) {
234            DocumentationItem docItem = descs.get(key);
235            String content = docItem.getContent();
236            if ("wiki".equals(docItem.getRenderingType())) {
237                Reader reader = new StringReader(content);
238                WikiSerializer engine = new WikiSerializer();
239                StringWriter writer = new StringWriter();
240                try {
241                    engine.serialize(reader, writer);
242                } catch (IOException | WikiParserException e) {
243                    throw new NuxeoException(e);
244                }
245                content = writer.getBuffer().toString();
246            } else {
247                content = "<div class='doc'>" + content + "</div>";
248            }
249            result.put(key, content);
250        }
251        return result;
252    }
253
254    @GET
255    @Produces("text/plain")
256    @Path("feedServices")
257    public String feedServices() throws JSONException {
258        List<String> serviceIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getServiceIds();
259
260        Map<String, String> descs = getRenderedDescriptions("NXService");
261
262        List<ArtifactLabel> serviceLabels = new ArrayList<ArtifactLabel>();
263
264        for (String id : serviceIds) {
265            serviceLabels.add(ArtifactLabel.createLabelFromService(id));
266        }
267        Collections.sort(serviceLabels);
268
269        JSONArray array = new JSONArray();
270
271        for (ArtifactLabel label : serviceLabels) {
272            JSONObject object = new JSONObject();
273            object.put("id", label.getId());
274            object.put("label", label.getLabel());
275            object.put("desc", descs.get(label.id));
276            object.put("url", "http://explorer.nuxeo.org/nuxeo/site/distribution/current/service2Bundle/" + label.id);
277            array.put(object);
278        }
279
280        return array.toString();
281    }
282
283    @GET
284    @Produces("text/plain")
285    @Path("feedExtensionPoints")
286    public String feedExtensionPoints() throws JSONException {
287        List<String> epIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getExtensionPointIds();
288
289        Map<String, String> descs = getRenderedDescriptions("NXExtensionPoint");
290
291        List<ArtifactLabel> labels = new ArrayList<ArtifactLabel>();
292
293        for (String id : epIds) {
294            labels.add(ArtifactLabel.createLabelFromExtensionPoint(id));
295        }
296        Collections.sort(labels);
297
298        JSONArray array = new JSONArray();
299
300        for (ArtifactLabel label : labels) {
301            JSONObject object = new JSONObject();
302            object.put("id", label.getId());
303            object.put("label", label.getLabel());
304            object.put("desc", descs.get(label.id));
305            object.put("url", "http://explorer.nuxeo.org/nuxeo/site/distribution/current/extensionPoint2Component/"
306                    + label.id);
307            array.put(object);
308        }
309
310        return array.toString();
311    }
312
313    @GET
314    @Produces("text/html")
315    @Path("filterServices")
316    public Object filterServices() {
317        String fulltext = getContext().getForm().getFormProperty("fulltext");
318        List<NuxeoArtifact> artifacts = getSearcher().filterArtifact(getContext().getCoreSession(), distributionId,
319                ServiceInfo.TYPE_NAME, fulltext);
320        List<String> serviceIds = new ArrayList<String>();
321        for (NuxeoArtifact item : artifacts) {
322            serviceIds.add(item.getId());
323        }
324        List<ArtifactLabel> serviceLabels = new ArrayList<ArtifactLabel>();
325
326        for (String id : serviceIds) {
327            serviceLabels.add(ArtifactLabel.createLabelFromService(id));
328        }
329        return getView("listServices").arg("services", serviceLabels).arg(Distribution.DIST_ID,
330                ctx.getProperty(Distribution.DIST_ID)).arg("searchFilter", fulltext);
331    }
332
333    @GET
334    @Produces("text/html")
335    @Path("listExtensionPointsSimple")
336    @SuppressWarnings("boxing")
337    public Object getExtensionPointsSimple() {
338        List<String> epIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getExtensionPointIds();
339
340        Map<String, Integer> epSimpleIds = new HashMap<String, Integer>();
341
342        List<ArtifactLabel> labels = new ArrayList<ArtifactLabel>();
343        for (String id : epIds) {
344            ArtifactLabel label = ArtifactLabel.createLabelFromExtensionPoint(id);
345            labels.add(label);
346            Integer count = epSimpleIds.get(label.simpleId);
347            if (count == null) {
348                count = 1;
349            } else {
350                count = count + 1;
351            }
352            epSimpleIds.put(label.simpleId, count);
353        }
354
355        for (ArtifactLabel label : labels) {
356            if (epSimpleIds.get(label.simpleId) == 1) {
357                label.label = label.simpleId;
358            }
359        }
360
361        Collections.sort(labels);
362        return getView("listExtensionPointsSimple").arg("eps", labels).arg(Distribution.DIST_ID,
363                ctx.getProperty(Distribution.DIST_ID)).arg("hideNav", Boolean.TRUE);
364    }
365
366    @GET
367    @Produces("text/html")
368    @Path("listExtensionPoints")
369    public Object getExtensionPoints() {
370        List<String> epIds = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getExtensionPointIds();
371
372        List<ArtifactLabel> labels = new ArrayList<ArtifactLabel>();
373        for (String id : epIds) {
374            labels.add(ArtifactLabel.createLabelFromExtensionPoint(id));
375        }
376
377        Collections.sort(labels);
378        return getView("listExtensionPoints").arg("eps", labels).arg(Distribution.DIST_ID,
379                ctx.getProperty(Distribution.DIST_ID));
380    }
381
382    @GET
383    @Produces("text/html")
384    @Path("filterExtensionPoints")
385    public Object filterExtensionPoints() {
386        String fulltext = getContext().getForm().getFormProperty("fulltext");
387        List<NuxeoArtifact> artifacts = getSearcher().filterArtifact(getContext().getCoreSession(), distributionId,
388                ExtensionPointInfo.TYPE_NAME, fulltext);
389        List<String> eps = new ArrayList<String>();
390        for (NuxeoArtifact item : artifacts) {
391            eps.add(item.getId());
392        }
393        List<ArtifactLabel> labels = new ArrayList<ArtifactLabel>();
394        for (String id : eps) {
395            labels.add(ArtifactLabel.createLabelFromExtensionPoint(id));
396        }
397        return getView("listExtensionPoints").arg("eps", labels).arg(Distribution.DIST_ID,
398                ctx.getProperty(Distribution.DIST_ID)).arg("searchFilter", fulltext);
399    }
400
401    @GET
402    @Produces("text/html")
403    @Path("listContributions")
404    public Object getContributions() {
405        DistributionSnapshot snapshot = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession());
406        List<String> cIds = snapshot.getContributionIds();
407        return getView("listContributions").arg("cIds", cIds).arg("contributions", snapshot.getContributions()).arg(
408                Distribution.DIST_ID, ctx.getProperty(Distribution.DIST_ID));
409    }
410
411    @GET
412    @Produces("text/html")
413    @Path("filterContributions")
414    public Object filterContributions() {
415        String fulltext = getContext().getForm().getFormProperty("fulltext");
416        List<NuxeoArtifact> artifacts = getSearcher().filterArtifact(getContext().getCoreSession(), distributionId,
417                ExtensionPointInfo.TYPE_NAME, fulltext);
418        List<String> cIds = new ArrayList<String>();
419        for (NuxeoArtifact item : artifacts) {
420            cIds.add(item.getId());
421        }
422        return getView("listContributions").arg("cIds", cIds).arg(Distribution.DIST_ID,
423                ctx.getProperty(Distribution.DIST_ID)).arg("searchFilter", fulltext);
424    }
425
426    @Path("doc")
427    public Resource viewDoc() {
428        return ctx.newObject("documentation");
429    }
430
431    @GET
432    @Produces("text/html")
433    @Path("service2Bundle/{serviceId}")
434    public Object service2Bundle(@PathParam("serviceId") String serviceId) {
435
436        ServiceInfo si = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getService(serviceId);
437        if (si == null) {
438            return null;
439        }
440        String cid = si.getComponentId();
441
442        ComponentInfo ci = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getComponent(cid);
443        String bid = ci.getBundle().getId();
444
445        org.nuxeo.common.utils.Path target = new org.nuxeo.common.utils.Path(getContext().getRoot().getName());
446        target = target.append(distributionId);
447        target = target.append("viewBundle");
448        target = target.append(bid + "#Service." + serviceId);
449        try {
450            return Response.seeOther(new URI(target.toString())).build();
451        } catch (URISyntaxException e) {
452            throw new NuxeoException(e);
453        }
454    }
455
456    @GET
457    @Produces("text/html")
458    @Path("extensionPoint2Component/{epId}")
459    public Object extensionPoint2Component(@PathParam("epId") String epId) {
460
461        ExtensionPointInfo epi = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession()).getExtensionPoint(
462                epId);
463        if (epi == null) {
464            return null;
465        }
466        String cid = epi.getComponent().getId();
467
468        org.nuxeo.common.utils.Path target = new org.nuxeo.common.utils.Path(getContext().getRoot().getName());
469        target = target.append(distributionId);
470        target = target.append("viewComponent");
471        target = target.append(cid + "#extensionPoint." + epId);
472        try {
473            return Response.seeOther(new URI(target.toString())).build();
474        } catch (URISyntaxException e) {
475            throw new NuxeoException(e);
476        }
477    }
478
479    @Path("viewBundle/{bundleId}")
480    public Resource viewBundle(@PathParam("bundleId") String bundleId) {
481        NuxeoArtifactWebObject wo = (NuxeoArtifactWebObject) ctx.newObject("bundle", bundleId);
482        NuxeoArtifact nxItem = wo.getNxArtifact();
483        if (nxItem == null) {
484            throw new WebResourceNotFoundException(bundleId);
485        }
486        TreeHelper.updateTree(getContext(), nxItem.getHierarchyPath());
487        return wo;
488    }
489
490    @Path("viewComponent/{componentId}")
491    public Resource viewComponent(@PathParam("componentId") String componentId) {
492        NuxeoArtifactWebObject wo = (NuxeoArtifactWebObject) ctx.newObject("component", componentId);
493        NuxeoArtifact nxItem = wo.getNxArtifact();
494        if (nxItem == null) {
495            throw new WebResourceNotFoundException(componentId);
496        }
497        TreeHelper.updateTree(getContext(), nxItem.getHierarchyPath());
498        return wo;
499    }
500
501    @Path("viewSeamComponent/{componentId}")
502    public Resource viewSeamComponent(@PathParam("componentId") String componentId) {
503        return (NuxeoArtifactWebObject) ctx.newObject("seamComponent", componentId);
504    }
505
506    @Path("viewOperation/{opId}")
507    public Resource viewOperation(@PathParam("opId") String opId) {
508        return (NuxeoArtifactWebObject) ctx.newObject("operation", opId);
509    }
510
511    @Path("viewService/{serviceId}")
512    public Resource viewService(@PathParam("serviceId") String serviceId) {
513        NuxeoArtifactWebObject wo = (NuxeoArtifactWebObject) ctx.newObject("service", serviceId);
514        NuxeoArtifact nxItem = wo.getNxArtifact();
515        if (nxItem == null) {
516            throw new WebResourceNotFoundException(serviceId);
517        }
518        TreeHelper.updateTree(getContext(), nxItem.getHierarchyPath());
519        return wo;
520    }
521
522    @Path("viewExtensionPoint/{epId}")
523    public Resource viewExtensionPoint(@PathParam("epId") String epId) {
524        NuxeoArtifactWebObject wo = (NuxeoArtifactWebObject) ctx.newObject("extensionPoint", epId);
525        NuxeoArtifact nxItem = wo.getNxArtifact();
526        if (nxItem == null) {
527            throw new WebResourceNotFoundException(epId);
528        }
529        TreeHelper.updateTree(getContext(), nxItem.getHierarchyPath());
530        return wo;
531    }
532
533    @Path("viewContribution/{cId}")
534    public Resource viewContribution(@PathParam("cId") String cId) {
535        NuxeoArtifactWebObject wo = (NuxeoArtifactWebObject) ctx.newObject("contribution", cId);
536        NuxeoArtifact nxItem = wo.getNxArtifact();
537        if (nxItem == null) {
538            throw new WebResourceNotFoundException(cId);
539        }
540        TreeHelper.updateTree(getContext(), nxItem.getHierarchyPath());
541        return wo;
542    }
543
544    @Path("viewBundleGroup/{gId}")
545    public Resource viewBundleGroup(@PathParam("gId") String gId) {
546        NuxeoArtifactWebObject wo = (NuxeoArtifactWebObject) ctx.newObject("bundleGroup", gId);
547        NuxeoArtifact nxItem = wo.getNxArtifact();
548        if (nxItem == null) {
549            throw new WebResourceNotFoundException(gId);
550        }
551        TreeHelper.updateTree(getContext(), nxItem.getHierarchyPath());
552        return wo;
553    }
554
555    @Path("viewArtifact/{id}")
556    public Object viewArtifact(@PathParam("id") String id) {
557        DistributionSnapshot snap = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession());
558
559        BundleGroup bg = snap.getBundleGroup(id);
560        if (bg != null) {
561            return viewBundleGroup(id);
562        }
563
564        BundleInfo bi = snap.getBundle(id);
565        if (bi != null) {
566            return viewBundle(id);
567        }
568
569        ComponentInfo ci = snap.getComponent(id);
570        if (ci != null) {
571            return viewComponent(id);
572        }
573
574        ServiceInfo si = snap.getService(id);
575        if (si != null) {
576            return viewService(id);
577        }
578
579        ExtensionPointInfo epi = snap.getExtensionPoint(id);
580        if (epi != null) {
581            return viewExtensionPoint(id);
582        }
583
584        ExtensionInfo ei = snap.getContribution(id);
585        if (ei != null) {
586            return viewContribution(id);
587        }
588
589        return Response.status(404).build();
590    }
591
592    public String getLabel(String id) {
593        return null;
594    }
595
596    @GET
597    @Produces("text/html")
598    @Path("listSeamComponents")
599    public Object listSeamComponents() {
600        return dolistSeamComponents("listSeamComponents", false);
601    }
602
603    @GET
604    @Produces("text/html")
605    @Path("listSeamComponentsSimple")
606    public Object listSeamComponentsSimple() {
607        return dolistSeamComponents("listSeamComponentsSimple", true);
608    }
609
610    protected Object dolistSeamComponents(String view, boolean hideNav) {
611
612        getSnapshotManager().initSeamContext(getContext().getRequest());
613
614        DistributionSnapshot snap = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession());
615        List<SeamComponentInfo> seamComponents = snap.getSeamComponents();
616        return getView(view).arg("seamComponents", seamComponents).arg(Distribution.DIST_ID,
617                ctx.getProperty(Distribution.DIST_ID)).arg("hideNav", Boolean.valueOf(hideNav));
618    }
619
620    @GET
621    @Produces("text/html")
622    @Path("listOperations")
623    public Object listOperations() {
624        DistributionSnapshot snap = getSnapshotManager().getSnapshot(distributionId, ctx.getCoreSession());
625        List<OperationInfo> operations = snap.getOperations();
626        return getView("listOperations").arg("operations", operations).arg(Distribution.DIST_ID,
627                ctx.getProperty(Distribution.DIST_ID)).arg("hideNav", Boolean.valueOf(false));
628    }
629
630}