/* (c) 2014 Open Source Geospatial Foundation - all rights reserved * (c) 2001 - 2013 OpenPlans * This code is licensed under the GPL 2.0 license, available at the root * application directory. */ package org.geoserver.script.rest; import java.util.Collection; import java.util.List; import org.apache.commons.io.FilenameUtils; import org.geoserver.platform.resource.Resource.Type; import org.geoserver.platform.resource.Resources; import org.geoserver.rest.PageInfo; import org.geoserver.rest.ReflectiveResource; import org.geoserver.rest.format.DataFormat; import org.geoserver.rest.format.ReflectiveHTMLFormat; import org.geoserver.rest.format.ReflectiveXMLFormat; import org.geoserver.script.ScriptManager; import org.geoserver.util.Filter; import org.restlet.data.Request; import org.restlet.data.Response; import org.restlet.resource.Resource; import com.google.common.collect.Lists; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.converters.Converter; import com.thoughtworks.xstream.converters.MarshallingContext; import com.thoughtworks.xstream.converters.UnmarshallingContext; import com.thoughtworks.xstream.converters.collections.CollectionConverter; import com.thoughtworks.xstream.io.HierarchicalStreamReader; import com.thoughtworks.xstream.io.HierarchicalStreamWriter; import freemarker.template.Configuration; /** * Resource that lists all available scripts as a JSON array of strings. * * @author Justin Deoliveira, OpenGeo */ public class ScriptListResource extends ReflectiveResource { ScriptManager scriptMgr; String path; public ScriptListResource(ScriptManager scriptMgr, String path, Request request, Response response) { super(null, request, response); this.scriptMgr = scriptMgr; this.path = path; } @Override protected Object handleObjectGet() throws Exception { final String type = (String) getRequest().getAttributes().get("type"); org.geoserver.platform.resource.Resource dir = scriptMgr.script(path); List<Script> scripts = Lists.newArrayList(); if (dir != null) { Filter<org.geoserver.platform.resource.Resource> filter = type != null ? new Filter<org.geoserver.platform.resource.Resource>() { @Override public boolean accept(org.geoserver.platform.resource.Resource pathname) { return type.equalsIgnoreCase(FilenameUtils.getExtension(pathname.name())); } } : new Filter<org.geoserver.platform.resource.Resource>() { @Override public boolean accept(org.geoserver.platform.resource.Resource pathname) { return true; } }; for (org.geoserver.platform.resource.Resource f : Resources.list(dir, filter)) { if (path.equals("apps")) { org.geoserver.platform.resource.Resource mainScript = scriptMgr.findAppMainScript(f); if (mainScript != null) { String name = mainScript.path().substring( f.parent().path().length() + 1).replace("\\", "/"); scripts.add(new Script(name)); } } else if (path.equals("wps")) { if (f.getType() == Type.DIRECTORY) { String namespace = f.name(); List<org.geoserver.platform.resource.Resource> files = f.list(); for(org.geoserver.platform.resource.Resource file: files) { String name = namespace + ":" + file.name(); scripts.add(new Script(name)); } } else { String name = f.name(); scripts.add(new Script(name)); } } else { String name = f.name(); scripts.add(new Script(name)); } } } else { // return empty array, perhaps we should return a 404? // throw new RestletException(format("Could not find script dir %s", // path), // Status.CLIENT_ERROR_NOT_FOUND); } return scripts; } @Override protected void configureXStream(XStream xstream) { super.configureXStream(xstream); xstream.alias("script", Script.class); xstream.alias("scripts", List.class); final String name = "script"; xstream.registerConverter(new CollectionConverter(xstream.getMapper()) { public boolean canConvert(Class type) { return Collection.class.isAssignableFrom(type); }; @Override protected void writeItem(Object item, MarshallingContext context, HierarchicalStreamWriter writer) { writer.startNode(name); context.convertAnother(item); writer.endNode(); } }); xstream.registerConverter(new Converter() { public boolean canConvert(Class type) { return Script.class.isAssignableFrom(type); } public void marshal(Object source, HierarchicalStreamWriter writer, MarshallingContext context) { String name = ((Script) source).getName(); writer.startNode("name"); writer.setValue(name); writer.endNode(); encodeLink(name, writer); } public Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext context) { return null; } }); } protected void encodeAlternateAtomLink(String link, HierarchicalStreamWriter writer) { encodeAlternateAtomLink(link, writer, getFormatGet()); } protected void encodeAlternateAtomLink(String link, HierarchicalStreamWriter writer, DataFormat format) { writer.startNode("atom:link"); writer.addAttribute("xmlns:atom", "http://www.w3.org/2005/Atom"); writer.addAttribute("rel", "alternate"); writer.addAttribute("href", href(link, format)); if (format != null) { writer.addAttribute("type", format.getMediaType().toString()); } writer.endNode(); } protected void encodeLink(String link, HierarchicalStreamWriter writer) { encodeLink(link, writer, getFormatGet()); } protected String href(String link, DataFormat format) { PageInfo pg = getPageInfo(); // encode as relative or absolute depending on the link type if (link.startsWith("/")) { // absolute, encode from "root" return pg.rootURI(link); } else { // encode as relative return pg.pageURI(link); } } protected void encodeLink(String link, HierarchicalStreamWriter writer, DataFormat format) { if (getFormatGet() instanceof ReflectiveXMLFormat) { // encode as an atom link encodeAlternateAtomLink(link, writer, format); } else { // encode as a child element writer.startNode("href"); writer.setValue(href(link, format)); writer.endNode(); } } @Override protected DataFormat createHTMLFormat(Request request, Response response) { return new ScriptHTMLFormat(request, response, this); } private static class ScriptHTMLFormat extends ReflectiveHTMLFormat { public ScriptHTMLFormat(Request request, Response response, Resource resource) { super(Script.class, request, response, resource); } @Override protected Configuration createConfiguration(Object data, Class clazz) { final Configuration cfg = super.createConfiguration(data, clazz); cfg.setClassForTemplateLoading(getClass(), "templates"); return cfg; } @Override protected String getTemplateName(Object data) { return "script.ftl"; } } public static class Script { private String name; public Script(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return name; } } }