Skip to content
Snippets Groups Projects
Commit 2671561b authored by Tor-Einar Skog's avatar Tor-Einar Skog
Browse files

First working version with JSON Serialization of configuration and result objects

parent deb09a55
No related branches found
No related tags found
No related merge requests found
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
<groupId>org.jboss.resteasy</groupId> <groupId>org.jboss.resteasy</groupId>
<artifactId>resteasy-jaxrs</artifactId> <artifactId>resteasy-jaxrs</artifactId>
<version>3.0.2.Final</version> <version>3.0.2.Final</version>
<scope>provided</scope>
</dependency> </dependency>
<dependency> <dependency>
<groupId>javax.persistence</groupId> <groupId>javax.persistence</groupId>
...@@ -40,6 +41,33 @@ ...@@ -40,6 +41,33 @@
<version>1.1</version> <version>1.1</version>
<scope>provided</scope> <scope>provided</scope>
</dependency> </dependency>
<dependency>
<groupId>org.reflections</groupId>
<artifactId>reflections</artifactId>
<version>0.9.9-RC1</version>
</dependency>
<dependency>
<groupId>no.bioforsk.vips.common</groupId>
<artifactId>VIPSCommon</artifactId>
<version>1.0-SNAPSHOT</version>
<!--scope>provided</scope-->
</dependency>
<dependency>
<groupId>no.bioforsk.vips.</groupId>
<artifactId>TestModel</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>com.thetransactioncompany</groupId>
<artifactId>cors-filter</artifactId>
<version>1.7.1</version>
</dependency>
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-web-api</artifactId>
<version>6.0</version>
<type>jar</type>
</dependency>
</dependencies> </dependencies>
<build> <build>
...@@ -63,7 +91,7 @@ ...@@ -63,7 +91,7 @@
<name>copyright</name> <name>copyright</name>
<!-- copyright tag for classes and interfaces --> <!-- copyright tag for classes and interfaces -->
<placement>t</placement> <placement>t</placement>
<head>&copy;</head> <head>&copy; Copyright</head>
</tag> </tag>
</tags> </tags>
</configuration> </configuration>
......
...@@ -4,6 +4,11 @@ import java.util.Set; ...@@ -4,6 +4,11 @@ import java.util.Set;
import javax.ws.rs.ApplicationPath; import javax.ws.rs.ApplicationPath;
import javax.ws.rs.core.Application; import javax.ws.rs.core.Application;
/**
* Responsible for adding REST resources
* @copyright 2013 {@link http://www.bioforsk.no Bioforsk}
* @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
*/
@ApplicationPath("/") @ApplicationPath("/")
public class VIPSCoreApplication extends Application public class VIPSCoreApplication extends Application
{ {
...@@ -20,6 +25,8 @@ public class VIPSCoreApplication extends Application ...@@ -20,6 +25,8 @@ public class VIPSCoreApplication extends Application
* given list with all resources defined in the project. * given list with all resources defined in the project.
*/ */
private void addRestResourceClasses(Set<Class<?>> resources) { private void addRestResourceClasses(Set<Class<?>> resources) {
resources.add(no.bioforsk.vips.core.service.TestResource.class); resources.add(no.bioforsk.vips.core.service.ModelResource.class);
} }
} }
\ No newline at end of file
package no.bioforsk.vips.core.entities;
import java.util.Date;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
*
* @author treinar
*/
//@XmlRootElement(name="weather")
//@XmlAccessorType(XmlAccessType.FIELD)
public class Weather {
public Weather()
{
}
public Weather(Date date, String details){
this.setDate(date);
this.setDetails(details);
}
//@XmlAttribute
private Date date;
//@XmlElement
private String details;
/**
* @return the date
*/
public Date getDate() {
return date;
}
/**
* @param date the date to set
*/
public void setDate(Date date) {
this.date = date;
}
/**
* @return the details
*/
public String getDetails() {
return details;
}
/**
* @param details the details to set
*/
public void setDetails(String details) {
this.details = details;
}
}
package no.bioforsk.vips.core.service;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.ws.rs.Consumes;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import no.bioforsk.vips.entity.ModelConfiguration;
import no.bioforsk.vips.entity.Result;
import no.bioforsk.vips.entity.ResultImpl;
import no.bioforsk.vips.entity.Weather;
import no.bioforsk.vips.model.Model;
import no.bioforsk.vips.model.factory.ModelFactory;
/**
* The available resources in this system
* @copyright 2013 {@link http://www.bioforsk.no Bioforsk}
* @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
*/
@Path("")
public class ModelResource {
/**
* Lists all models available in this instance
* @return
*/
@GET
@Path("models")
@Produces("text/plain;charset=UTF-8")
public Response printModels()
{
StringBuilder retVal = new StringBuilder();
ModelFactory mF = ModelFactory.getInstance();
for(String key : mF.getModelList().keySet())
{
retVal.append(key).append("\n");
}
return Response.ok().entity(retVal.toString()).build();
}
/**
* Prints the usage instructions from the requested model
* @param modelId
* @return
*/
@GET
@Path("models/{modelId}/usage")
@Produces("text/plain;charset=UTF-8")
public Response printModelUsage(@PathParam("modelId") String modelId)
{
String usage = ModelFactory.getInstance().getModelUsage(modelId);
return Response.ok().entity(usage).build();
}
/** Tests for XML and JSON output */
@GET
@Path("models/resulttest")
@Produces("application/json")
public Response printResultTest()
{
List<Result> allResults = new ArrayList();
Result retVal = new ResultImpl();
retVal.setResultValidTime(new Date());
retVal.setValue("Parameter1", "Verdi1");
retVal.setValue("Parameter2", "Verdi2");
allResults.add(retVal);
retVal = new ResultImpl();
retVal.setResultValidTime(new Date());
retVal.setValue("Parameter1", "Verdi5");
retVal.setValue("Parameter2", "Verdi7");
allResults.add(retVal);
return Response.ok().entity(allResults).build();
}
@GET
@Path("weather/xml")
@Produces("application/xml")
public Response printWeatherXML()
{
return Response.ok().entity(new Weather(new Date(),"Goddag, goddag. Dette her er Meteorologisk institutt.æøåæøå")).build();
}
/**
* Marshalling fra POJO til JSON gjøres automagisk (med Jackson, tror jeg)
* @return gladmelding
*/
@GET
@Path("weather/json")
@Produces("application/json")
public Response printWeatherJSON()
{
return Response.ok().entity(new Weather(new Date(),"Goddag, goddag. Dette her er Meteorologisk institutt.æøåæøå")).build();
}
/**
* Test for input / POST
*/
@POST
@Path("models/run")
@Consumes("application/json")
@Produces("application/json")
//@Produces("text/plain;charset=UTF-8")
public Response runModel(ModelConfiguration config)
{
//return Response.ok().entity("runModell called").build();
try
{
Model calledModel = ModelFactory.getInstance().getModelInstance(config.getModelId());
return Response.ok().entity(calledModel.getResult()).build();
}
catch(InstantiationException | IllegalAccessException iae)
{
return Response.serverError().build();
}
}
}
package no.bioforsk.vips.core.service;
import java.util.Date;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;
import no.bioforsk.vips.core.entities.Weather;
/**
*
* @copyright Bioforsk.no
* @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
*/
@Path("test")
public class TestResource {
@GET
@Path("Hello/{name}")
public Response printMessageHolihili(@PathParam("name") String name){
return Response.ok().entity("Neimen heisann, " + name).build();
};
@GET
@Path("weather/xml")
@Produces("application/xml")
public Weather printWeatherXML()
{
return new Weather(new Date(),"Goddag, goddag. Dette her er Meteorologisk institutt.");
}
/**
* Marshalling fra POJO til JSON gjøres automagisk (med Jackson, tror jeg)
* @return gladmelding
*/
@GET
@Path("weather/json")
@Produces("application/json")
public Response printWeatherJSON()
{
return Response.ok().entity(new Weather(new Date(),"Goddag, goddag. Dette her er Meteorologisk institutt.")).build();
}
}
package no.bioforsk.vips.core.startup;
import javax.servlet.ServletContextEvent;
import no.bioforsk.vips.model.factory.ModelFactory;
/**
* This class is created and method contextInitialized called when the application
* is deployed (either at startup of application container or when redeploying the app)
*
* @copyright 2013 {@link http://www.bioforsk.no Bioforsk}
* @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
*/
public class StartupListener implements javax.servlet.ServletContextListener{
/**
* Called when the application
* is deployed (either at startup of application container or when redeploying the app)
* @param sce
*/
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("VIPSCore system initializing");
// We create the singleton instance of ModelFactory at startup, as this
// takes a few seconds (due to scanning of file system)
ModelFactory singletonFactory = ModelFactory.getInstance();
}
/**
* Called when the web app is closed
* @param sce
*/
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("VIPSCore system shutting down");
}
}
package no.bioforsk.vips.model.factory;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.reflections.Reflections;
import no.bioforsk.vips.model.Model;
/**
* Provides the models available. Singleton.
*
* <h2>Deploying models</h2>
* To make a model available, it must
* <ul>
* <li>Implement the {@link no.bioforsk.vips.model.Model} interface</li>
* <li>
* Be on the class path of the running application, preferably in a separate JAR.
* The guaranteed way to make it work is to put it inside the VIPSCore WAR-file, in /WEB-INF/lib
* This could be accomplished most easily by using a ZIP application, or accessing
* The VIPSCore source and building it with the JAR(s) as (a) dependenc(y/ies)
* </li>
* </ul>
*
* @copyright 2013 {@link http://www.bioforsk.no Bioforsk}
* @author Tor-Einar Skog <tor-einar.skog@bioforsk.no>
*/
public class ModelFactory {
// The singleton instance
private static ModelFactory modelFactory;
// Internal collection of models found from scanning the class path
private Map<String,Model> models;
// Internal list of model IDs and names
private Map<String,String> modelList;
/**
* Declared private to protect from unauthorized instatiation. Part of the
* Singleton design pattern.
*/
private ModelFactory()
{
this.init();
}
/**
* Overriding {@link java.lang.Object}'s clone() method to prevent cloning.
* Part of the Singleton design pattern.
* @return
* @throws CloneNotSupportedException
*/
@Override
public Object clone() throws CloneNotSupportedException {
throw new CloneNotSupportedException();
}
/**
* Use this method to get the singleton instance of the class
* @return an instance (the only one in the JVM) of ModelFactory
*/
public static synchronized ModelFactory getInstance(){
if(modelFactory == null)
{
modelFactory = new ModelFactory();
}
return modelFactory;
}
/**
* Scans the whole class path for classes implementing the Model interface.
* Builds an inventory.
*/
private void init(){
/*
* Reflections API insists on using at least one package prefix. So we scan
* through all TLDs. List is compiled from
* http://en.wikipedia.org/wiki/List_of_Internet_top-level_domains
*/
String[] defaultTopDomains = {
"aero","asia","biz","cat","com","coop","info","int","jobs","mobi",
"museum","name","net","org","post","pro","tel","travel","edu","gov",
"ac","ad","ae","af","ag","ai","al","am","an","ao","aq","ar","as","at",
"au","aw","ax","az","ba","bb","bd","be","bf","bg","bh","bi","bj","bm",
"bn","bo","br","bs","bt","bv","bw","by","bz","ca","cc","cd","cf","cg",
"ch","ci","ck","cl","cm","cn","co","cr","cs","cu","cv","cx","cy","cz",
"dd","de","dj","dk","dm","do","dz","ec","ee","eg","eh","er","es","et",
"eu","fi","fj","fk","fm","fo","fr","ga","gb","gd","ge","gf","gg","gh",
"gi","gl","gm","gn","gp","gq","gr","gs","gt","gu","gw","gy","hk","hm",
"hn","hr","ht","hu","id","ie","il","im","in","io","iq","ir","is","it",
"je","jm","jo","jp","ke","kg","kh","ki","km","kn","kp","kr","kw","ky",
"kz","la","lb","lc","li","lk","lr","ls","lt","lu","lv","ly","ma","mc",
"md","me","mg","mh","mk","ml","mm","mn","mo","mp","mq","mr","ms","mt",
"mu","mv","mw","mx","my","mz","na","nc","ne","nf","ng","ni","nl","no",
"np","nr","nu","nz","om","pa","pe","pf","pg","ph","pk","pl","pm","pn",
"pr","ps","pt","pw","py","qa","re","ro","rs","ru","rw","sa","sb","sc",
"sd","se","sg","sh","si","sj","sk","sl","sm","sn","so","sr","ss","st",
"su","sv","sx","sy","sz","tc","td","tf","tg","th","tj","tk","tl","tm",
"tn","to","tp","tr","tt","tv","tw","tz","ua","ug","uk","us","uy","uz",
"va","vc","ve","vg","vi","vn","vu","wf","ws","ye","yt","yu","za","zm",
"zw",
};
/**
* Warning: This generates a WARNING from a filesystem/JARfile scan error
* for each TLD not found. Use application container's config to suppress
* this in log files.
*/
Reflections reflections;
Set<Class<? extends Model>> subTypes = new HashSet();
for(String topDomain: defaultTopDomains)
{
reflections = new Reflections(topDomain);
subTypes.addAll(reflections.getSubTypesOf(Model.class));
}
/**
* Iterates and instantiates one object for each class
*/
this.models = new HashMap();
for(Class<? extends Model> subType : subTypes)
{
try {
Model model = subType.newInstance();
models.put(model.getModelId().toString(), model);
//System.out.println("Model " + model.getModelName() + " with id=" + model.getModelId().toString() + " was found");
} catch ( InstantiationException | IllegalAccessException ex) {
Logger.getLogger(ModelFactory.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
/**
* TODO: Add support for locale
* @return a list of all the available models in this JVM
*/
public synchronized Map<String,String> getModelList()
{
if(this.modelList == null)
{
this.modelList = new HashMap();
for(Model model:this.models.values())
{
this.modelList.put(model.getModelId().toString(), model.getModelName());
}
}
return this.modelList;
}
/**
* TODO: Add support for locale
* @param modelId the id of the Model
* @return usage instructions for the requested Model
*
*/
public String getModelUsage(String modelId)
{
return this.models.get(modelId).getModelUsage();
}
/**
*
* @param modelId the id of the Model
* @return a new instance of the model with the given Id
* @throws InstantiationException
* @throws IllegalAccessException
*/
public Model getModelInstance(String modelId) throws InstantiationException, IllegalAccessException
{
return this.models.get(modelId).getClass().newInstance();
}
}
<?xml version="1.0" encoding="UTF-8" standalone="no"?> <?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" version="3.0" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<listener>
<listener-class>no.bioforsk.vips.core.startup.StartupListener</listener-class>
</listener>
<!-- This is for allowing Cross-Site requests -->
<filter>
<filter-name>CORS</filter-name>
<filter-class>com.thetransactioncompany.cors.CORSFilter</filter-class>
<init-param>
<param-name>cors.supportedMethods</param-name>
<param-value>GET, POST, HEAD, PUT, DELETE, OPTIONS</param-value>
</init-param>
<init-param>
<!-- fix for http://code.google.com/p/chromium/issues/detail?id=108394 -->
<param-name>cors.supportedHeaders</param-name>
<param-value>Origin, Content-type, Accept</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CORS</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app> </web-app>
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment