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