From c75ef352b8ddc84acc5caa9f9d9ef2c440b64550 Mon Sep 17 00:00:00 2001 From: Jonathan Anstey Date: Thu, 11 Jun 2009 16:57:34 +0000 Subject: [PATCH] CAMEL-1655 - Add support for saving Groovy and Ruby route code. Viewing as Groovy or Ruby is TBD. Thanks to Xueqiang Mi for this contribution! git-svn-id: https://svn.apache.org/repos/asf/camel/trunk@783847 13f79535-47bb-0310-9956-ffa450edef68 --- components/camel-web/pom.xml | 8 + .../camel/web/resources/RouteResource.java | 240 ++++++++++++++++-- .../web/resources/RouteResource/edit.jsp | 41 +-- 3 files changed, 244 insertions(+), 45 deletions(-) diff --git a/components/camel-web/pom.xml b/components/camel-web/pom.xml index 9848711f27f8a..88e04da34fc72 100644 --- a/components/camel-web/pom.xml +++ b/components/camel-web/pom.xml @@ -72,6 +72,14 @@ org.apache.camel camel-spring + + org.apache.camel + camel-groovy + + + org.apache.camel + camel-ruby + com.sun.jersey.contribs jersey-spring diff --git a/components/camel-web/src/main/java/org/apache/camel/web/resources/RouteResource.java b/components/camel-web/src/main/java/org/apache/camel/web/resources/RouteResource.java index aa3e0184fd361..259ba4e9091af 100644 --- a/components/camel-web/src/main/java/org/apache/camel/web/resources/RouteResource.java +++ b/components/camel-web/src/main/java/org/apache/camel/web/resources/RouteResource.java @@ -16,12 +16,15 @@ */ package org.apache.camel.web.resources; +import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.io.StringReader; import java.io.StringWriter; import java.net.URI; import java.net.URISyntaxException; import java.util.Collections; +import java.util.List; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -39,12 +42,17 @@ import com.sun.jersey.api.representation.Form; import com.sun.jersey.api.view.Viewable; +import groovy.lang.GroovyClassLoader; +import org.apache.camel.builder.RouteBuilder; +import org.apache.camel.impl.DefaultCamelContext; import org.apache.camel.model.RouteDefinition; +import org.apache.camel.ruby.RubyCamel; import org.apache.camel.util.ObjectHelper; import org.apache.camel.view.RouteDotGenerator; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; +import org.jruby.Main; /** * A single Camel Route which is used to implement one or more @@ -54,11 +62,23 @@ */ public class RouteResource extends CamelChildResourceSupport { private static final transient Log LOG = LogFactory.getLog(RouteResource.class); + private static final String LANGUAGE_XML = "Xml"; + private static final String LANGUAGE_GROOVY = "Groovy"; + private static final String LANGUAGE_RUBY = "Ruby"; + private static final String LANGUAGE_SCALA = "Scala"; private RouteDefinition route; private String error = ""; private String id; + // what language is used to define this route + private String language = LANGUAGE_XML; + + // the route configuration: when language is Xml, the routeDefinition is + // null; when language is Groovy/Scala/Ruby, the routeDefinition contains + // the route definition class. It must be initialized because RouteResource + // is stateless. + private String routeDefinition = ""; public RouteResource(RoutesResource routesResource, RouteDefinition route) { super(routesResource.getContextResource()); @@ -83,15 +103,40 @@ public String getRouteXml() throws JAXBException { Marshaller marshaller = context.createMarshaller(); marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); // TODO fix to use "" namespace prefix - // using this https://jaxb.dev.java.net/nonav/2.1.10/docs/vendorProperties.html#prefixmapper + // using this + // https://jaxb.dev.java.net/nonav/2.1.10/docs/vendorProperties.html#prefixmapper StringWriter buffer = new StringWriter(); marshaller.marshal(route, buffer); return buffer.toString(); } /** - * Returns the Graphviz DOT Visualisation - * of this route + * Returns the language + */ + public String getLanguage() { + return language; + } + + /** + * Returns the content of the route definition class + */ + public String getRouteDefinition() { + if (language.equals(LANGUAGE_XML)) { + try { + return getRouteXml(); + } catch (JAXBException e) { + // e.printStackTrace(); + return "Error on marshal the route definition!"; + } + } else { + return routeDefinition; + } + } + + /** + * Returns the Graphviz DOT Visualisation of + * this route */ @GET @Produces(Constants.DOT_MIMETYPE) @@ -100,7 +145,6 @@ public String getDot() throws IOException { return generator.getRoutesText(getCamelContext()); } - /** * Allows a route definition to be updated */ @@ -115,45 +159,187 @@ public void postRoute(RouteDefinition routeDefinition) throws Exception { getCamelContext().addRouteDefinitions(Collections.singletonList(routeDefinition)); } + /** + * Allows a routes builder to be updated + */ + public void postRoutes(RouteBuilder builder) throws Exception { + // remove current route + DefaultCamelContext camelContext = (DefaultCamelContext)getCamelContext(); + camelContext.removeRouteDefinition(id); + + // lets install the updated routes + camelContext.addRoutes(builder); + } /** * Updates a route definition using form encoded data from a web form - * - * @param formData is the form data POSTed typically from a HTML form with the route field used to encode - * the XML text of the new route definition + * + * @param formData is the form data POSTed typically from a HTML form with + * the route field used to encode the XML text of + * the new route definition */ @POST @Consumes("application/x-www-form-urlencoded") public Response postRouteForm(@Context UriInfo uriInfo, Form formData) throws URISyntaxException { // TODO replace the Form class with an injected bean? - String xml = formData.getFirst("route", String.class); + String language = formData.getFirst("language", String.class); + String body = formData.getFirst("route", String.class); if (LOG.isDebugEnabled()) { - LOG.debug("new XML is: " + xml); + LOG.debug("new Route is: " + body); } - if (xml == null) { - error = "No XML submitted!"; - } else { - try { - JAXBContext context = JAXBContext.newInstance(Constants.JAXB_PACKAGES); - Unmarshaller unmarshaller = context.createUnmarshaller(); - Object value = unmarshaller.unmarshal(new StringReader(xml)); - if (value instanceof RouteDefinition) { - RouteDefinition routeDefinition = (RouteDefinition) value; - postRoute(routeDefinition); - return Response.seeOther(new URI("/routes")).build(); - } else { - error = "Posted XML is not a route but is of type " + ObjectHelper.className(value); - } - } catch (JAXBException e) { - error = "Failed to parse XML: " + e.getMessage(); - } catch (Exception e) { - error = "Failed to install route: " + e.getMessage(); + LOG.info(body); + if (body == null) { + error = "No Route submitted!"; + } else if (language.equals(LANGUAGE_XML)) { + return parseXml(body); + } else if (language.equals(LANGUAGE_GROOVY)) { + return parseGroovy(body); + } else if (language.equals(LANGUAGE_RUBY)) { + return parseRuby(body); + } else if (language.equals(LANGUAGE_SCALA)) { + return parseScala(body); + } + error = "Not supproted language!"; + return Response.ok(new Viewable("edit", this)).build(); + + } + + /** + * process the route configuration defined in Xml + */ + private Response parseXml(String xml) { + try { + JAXBContext context = JAXBContext.newInstance(Constants.JAXB_PACKAGES); + Unmarshaller unmarshaller = context.createUnmarshaller(); + Object value = unmarshaller.unmarshal(new StringReader(xml)); + if (value instanceof RouteDefinition) { + RouteDefinition routeDefinition = (RouteDefinition)value; + postRoute(routeDefinition); + return Response.seeOther(new URI("/routes")).build(); + } else { + error = "Posted XML is not a route but is of type " + ObjectHelper.className(value); + } + } catch (JAXBException e) { + error = "Failed to parse XML: " + e.getMessage(); + } catch (Exception e) { + error = "Failed to install route: " + e.getMessage(); + } + // lets re-render the form + return Response.ok(new Viewable("edit", this)).build(); + } + + /** + * process the route configuration defined in Groovy class + */ + private Response parseGroovy(String route) { + try { + // store the route definition + File file = storeRoute(route, LANGUAGE_GROOVY); + + // load the definition class into a RouteBuilder instance + GroovyClassLoader classLoader = new GroovyClassLoader(); + Class clazz = classLoader.parseClass(file); + RouteBuilder builder = (RouteBuilder)clazz.newInstance(); + LOG.info("Loaded builder: " + builder); + + postRoutes(builder); + + return Response.seeOther(new URI("/routes")).build(); + + } catch (IOException e) { + // e.printStackTrace(); + error = "Failed to store the route: " + e.getMessage(); + } catch (InstantiationException e) { + // e.printStackTrace(); + error = "Failed to instantiate the route: " + e.getMessage(); + + } catch (IllegalAccessException e) { + // e.printStackTrace(); + error = "Failed to instantiate the route: " + e.getMessage(); + } catch (Exception e) { + // e.printStackTrace(); + error = "Failed to edit the route: " + e.getMessage(); + } + // lets re-render the form + return Response.ok(new Viewable("edit", this)).build(); + } + + /** + * process the route configuration defined in Ruby class + */ + private Response parseRuby(String route) { + try { + // add the script of addRouteBuilder into ruby script + route += "\n RubyCamel.addRouteBuilder(RubyRoute.new)"; + + // store the route definition + File file = storeRoute(route, LANGUAGE_RUBY); + + // execute the ruby script, which will store the RouteBuilder + // instances into RubyCamel + String[] args = {file.getAbsolutePath()}; + Main.main(args); + + // get the route builders from the RubyCamel and add them into this + // route + List list = RubyCamel.getRoutes(); + for (RouteBuilder builder : list) { + postRoutes(builder); } + + return Response.seeOther(new URI("/routes")).build(); + + } catch (IOException e) { + // e.printStackTrace(); + error = "Failed to store the route: " + e.getMessage(); + } catch (Exception e) { + // e.printStackTrace(); + error = "Failed to edit the route: " + e.getMessage(); + } // lets re-render the form return Response.ok(new Viewable("edit", this)).build(); } + /** + * process the route configuration defined in Scala class + */ + private Response parseScala(String route) { + try { + + // store the route definition + File file = storeRoute(route, LANGUAGE_SCALA); + + // load the definition class + + return Response.seeOther(new URI("/routes")).build(); + + } catch (IOException e) { + // e.printStackTrace(); + error = "Failed to store the route: " + e.getMessage(); + } catch (Exception e) { + // e.printStackTrace(); + error = "Failed to edit the route: " + e.getMessage(); + } + // lets re-render the form + return Response.ok(new Viewable("edit", this)).build(); + } + + /** + * Stores the route definition class into a file + */ + private File storeRoute(String route, String language) throws IOException { + // create a temporary file to store the route definition class + File file = File.createTempFile("Route-", "." + language); + FileWriter fw = new FileWriter(file); + + // write the route into the file + fw.write(route); + fw.flush(); + fw.close(); + return file; + } + /** * Looks up an individual route */ diff --git a/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp b/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp index 722014182c743..c7b2aae7eb9bf 100644 --- a/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp +++ b/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp @@ -1,28 +1,33 @@ - - - + + + - Edit ${it.route.id} +Edit ${it.route.id} -
" method="post"> +" + method="post"> - - - - - - - + + + + + + +
-

Edit ${it.route.id}

-
- -
- -
+

Edit ${it.route.id}

+
  as  
+
${it.error}