You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
229 lines
6.7 KiB
Java
229 lines
6.7 KiB
Java
package org.gcube.common.resources.gcore;
|
|
|
|
import java.io.ByteArrayInputStream;
|
|
import java.io.ByteArrayOutputStream;
|
|
import java.io.InputStream;
|
|
import java.io.OutputStream;
|
|
import java.io.OutputStreamWriter;
|
|
import java.io.Reader;
|
|
import java.io.Writer;
|
|
import java.util.HashMap;
|
|
import java.util.Map;
|
|
|
|
import javax.xml.XMLConstants;
|
|
import javax.xml.bind.JAXBContext;
|
|
import javax.xml.bind.Marshaller;
|
|
import javax.xml.bind.Unmarshaller;
|
|
import javax.xml.transform.Result;
|
|
import javax.xml.transform.Source;
|
|
import javax.xml.transform.stream.StreamResult;
|
|
import javax.xml.transform.stream.StreamSource;
|
|
import javax.xml.validation.Schema;
|
|
import javax.xml.validation.SchemaFactory;
|
|
|
|
import org.w3c.dom.bootstrap.DOMImplementationRegistry;
|
|
import org.w3c.dom.ls.DOMImplementationLS;
|
|
import org.w3c.dom.ls.LSInput;
|
|
import org.w3c.dom.ls.LSResourceResolver;
|
|
|
|
/**
|
|
* Utility methods over resources.
|
|
*
|
|
* @author Fabio Simeoni
|
|
* @author Luca Frosini (ISTI - CNR) http://www.lucafrosini.com/
|
|
*/
|
|
public class Resources {
|
|
|
|
private static SchemaFactory schemaFactory = SchemaFactory.newInstance(XMLConstants.W3C_XML_SCHEMA_NS_URI);
|
|
|
|
//known schema files embedded as classpath resources
|
|
private static Map<Class<?>, String> schemaResources = new HashMap<Class<?>, String>();
|
|
|
|
//cached schemas
|
|
private static Map<Class<?>,Schema> schemas = new HashMap<Class<?>, Schema>();
|
|
|
|
private static Map<Class<?>, JAXBContext> contexts = new HashMap<Class<?>, JAXBContext>();
|
|
|
|
|
|
static {
|
|
|
|
schemaFactory.setResourceResolver(new SchemaResolver());
|
|
|
|
//populates schema map
|
|
schemaResources.put(GenericResource.class, "schema/generic.xsd");
|
|
schemaResources.put(ServiceEndpoint.class, "schema/endpoint.xsd");
|
|
schemaResources.put(Software.class, "schema/service.xsd");
|
|
schemaResources.put(GCoreEndpoint.class, "schema/gcoreendpoint.xsd");
|
|
schemaResources.put(HostingNode.class, "schema/node.xsd");
|
|
|
|
//note: service instances have no schema so far
|
|
}
|
|
|
|
// helper: resolves common type declarations in schemas
|
|
private static class SchemaResolver implements LSResourceResolver {
|
|
|
|
private static LSInput input;
|
|
|
|
static {
|
|
try {
|
|
input = ((DOMImplementationLS) DOMImplementationRegistry.newInstance().getDOMImplementation("LS"))
|
|
.createLSInput();
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
public LSInput resolveResource(String type, String namespaceURI, String publicId, String systemId,
|
|
String baseURI) {
|
|
|
|
if (systemId.equals("CommonTypeDefinitions.xsd")) {
|
|
input.setByteStream(Resources.class.getResourceAsStream("/schema/CommonTypeDefinitions.xsd"));
|
|
}
|
|
return input;
|
|
}
|
|
};
|
|
|
|
/**
|
|
* Validates a resource against its own schema, if one exists.
|
|
* @param resource the resource
|
|
* @throws IllegalArgumentException if the resource has no associated scheme
|
|
* @throws Exception if the resource is not valid with respect to its own schema
|
|
*/
|
|
public static void validate(Resource resource) throws IllegalArgumentException, Exception {
|
|
|
|
Schema schema = schema(resource.getClass());
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
ByteArrayInputStream in = new ByteArrayInputStream(marshal(resource,out).toByteArray());
|
|
|
|
schema.newValidator().validate(new StreamSource(in));
|
|
|
|
|
|
}
|
|
|
|
//helper
|
|
private static synchronized Schema schema(Class<?> resourceClass) throws Exception {
|
|
|
|
String schemaResource = schemaResources.get(resourceClass);
|
|
|
|
if (schemaResource==null)
|
|
throw new IllegalArgumentException("no known schema for:\n "+resourceClass);
|
|
|
|
Schema schema = schemas.get(resourceClass);
|
|
if (schema==null) {
|
|
InputStream stream = Resources.class.getClassLoader().getResourceAsStream(schemaResource);
|
|
schema = schemaFactory.newSchema(new StreamSource(stream));
|
|
schemas.put(resourceClass,schema);
|
|
}
|
|
return schema;
|
|
}
|
|
|
|
/**
|
|
* Write the serialisation of a given resource to a given stream.
|
|
* @param resource the resource
|
|
* @param stream the stream in input
|
|
*/
|
|
public static <T extends OutputStream> T marshal(Object resource,T stream) {
|
|
|
|
marshal(resource, new StreamResult(stream));
|
|
return stream;
|
|
}
|
|
|
|
/**
|
|
* Write the serialisation of a given resource to a given character stream.
|
|
* @param resource the resource
|
|
* @param stream the stream in input
|
|
*/
|
|
public static <T extends Writer> T marshal(Object resource,T stream) {
|
|
|
|
marshal(resource,new StreamResult(stream));
|
|
return stream;
|
|
}
|
|
|
|
/**
|
|
* Write the serialisation of a given resource to a {@link Result}.
|
|
* @param resource the resource
|
|
* @param stream the result
|
|
* @return the result in input
|
|
*/
|
|
public static <T extends Result> T marshal(Object resource,T result) {
|
|
|
|
if (resource instanceof Resource)
|
|
((Resource) resource).lock.lock();
|
|
try {
|
|
JAXBContext context = context(resource.getClass());
|
|
Marshaller m = context.createMarshaller();
|
|
//m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
|
|
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
|
|
m.marshal(resource,result);
|
|
|
|
return result;
|
|
}
|
|
catch(Exception e) {
|
|
throw new RuntimeException("serialisation error",e);
|
|
} finally{
|
|
if (resource instanceof Resource)
|
|
((Resource) resource).lock.unlock();
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Prints the serialisation of a given resource to {@link System#out}
|
|
* @param resource the resource
|
|
*/
|
|
public static void print(Object resource) {
|
|
|
|
marshal(resource,new OutputStreamWriter(System.out));
|
|
}
|
|
|
|
/**
|
|
* Creates a resource of given class from its serialisation in a given {@link Reader}.
|
|
* @param resourceClass the class of the resource
|
|
* @param reader the reader
|
|
* @return the resource
|
|
*/
|
|
public static <T> T unmarshal(Class<T> resourceClass, Reader reader) {
|
|
return unmarshal(resourceClass,new StreamSource(reader));
|
|
}
|
|
|
|
/**
|
|
* Creates a resource of given class from its serialisation in a given {@link InputStream}.
|
|
* @param resourceClass the class of the resource
|
|
* @param stream the stream
|
|
* @return the resource
|
|
*/
|
|
public static <T> T unmarshal(Class<T> resourceClass, InputStream stream) {
|
|
return unmarshal(resourceClass,new StreamSource(stream));
|
|
}
|
|
|
|
/**
|
|
* Creates a resource of given class from its serialisation in a given {@link Source}.
|
|
* @param resourceClass the class of the resource
|
|
* @param source the source
|
|
* @return the resource
|
|
*/
|
|
public static <T> T unmarshal(Class<T> resourceClass,Source source) {
|
|
try {
|
|
JAXBContext ctx = context(resourceClass);
|
|
Unmarshaller um = ctx.createUnmarshaller();
|
|
return resourceClass.cast(um.unmarshal(source));
|
|
}
|
|
catch(Exception e) {
|
|
throw new RuntimeException("deserialisation error",e);
|
|
}
|
|
}
|
|
|
|
//helper
|
|
private static synchronized JAXBContext context(Class<?> resourceClass) throws Exception {
|
|
|
|
JAXBContext ctx = contexts.get(resourceClass);
|
|
if (ctx==null) {
|
|
ctx = JAXBContext.newInstance(resourceClass);
|
|
contexts.put(resourceClass,ctx);
|
|
}
|
|
return ctx;
|
|
|
|
}
|
|
}
|