421 lines
14 KiB
Java
421 lines
14 KiB
Java
|
/**
|
|||
|
* Copyright (C) 2007 - 2016 52°North Initiative for Geospatial Open Source
|
|||
|
* Software GmbH
|
|||
|
*
|
|||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|||
|
* you may not use this file except in compliance with the License.
|
|||
|
* You may obtain a copy of the License at
|
|||
|
*
|
|||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|||
|
*
|
|||
|
* Unless required by applicable law or agreed to in writing, software
|
|||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|||
|
* See the License for the specific language governing permissions and
|
|||
|
* limitations under the License.
|
|||
|
*/
|
|||
|
package org.n52.wps.server;
|
|||
|
|
|||
|
import java.lang.reflect.Constructor;
|
|||
|
import java.math.BigInteger;
|
|||
|
import java.util.ArrayList;
|
|||
|
import java.util.Iterator;
|
|||
|
import java.util.List;
|
|||
|
|
|||
|
import net.opengis.ows.x11.DomainMetadataType;
|
|||
|
import net.opengis.wps.x100.CRSsType;
|
|||
|
import net.opengis.wps.x100.ComplexDataCombinationType;
|
|||
|
import net.opengis.wps.x100.ComplexDataCombinationsType;
|
|||
|
import net.opengis.wps.x100.ComplexDataDescriptionType;
|
|||
|
import net.opengis.wps.x100.InputDescriptionType;
|
|||
|
import net.opengis.wps.x100.LiteralInputType;
|
|||
|
import net.opengis.wps.x100.LiteralOutputType;
|
|||
|
import net.opengis.wps.x100.OutputDescriptionType;
|
|||
|
import net.opengis.wps.x100.ProcessDescriptionType;
|
|||
|
import net.opengis.wps.x100.ProcessDescriptionType.DataInputs;
|
|||
|
import net.opengis.wps.x100.ProcessDescriptionType.ProcessOutputs;
|
|||
|
import net.opengis.wps.x100.ProcessDescriptionsDocument;
|
|||
|
import net.opengis.wps.x100.ProcessDescriptionsDocument.ProcessDescriptions;
|
|||
|
import net.opengis.wps.x100.SupportedCRSsType;
|
|||
|
import net.opengis.wps.x100.SupportedCRSsType.Default;
|
|||
|
import net.opengis.wps.x100.SupportedComplexDataInputType;
|
|||
|
import net.opengis.wps.x100.SupportedComplexDataType;
|
|||
|
|
|||
|
import org.n52.wps.FormatDocument.Format;
|
|||
|
import org.n52.wps.io.GeneratorFactory;
|
|||
|
import org.n52.wps.io.IGenerator;
|
|||
|
import org.n52.wps.io.IParser;
|
|||
|
import org.n52.wps.io.ParserFactory;
|
|||
|
import org.n52.wps.io.data.IBBOXData;
|
|||
|
import org.n52.wps.io.data.IComplexData;
|
|||
|
import org.n52.wps.io.data.ILiteralData;
|
|||
|
import org.n52.wps.server.observerpattern.IObserver;
|
|||
|
import org.n52.wps.server.observerpattern.ISubject;
|
|||
|
|
|||
|
|
|||
|
public abstract class AbstractSelfDescribingAlgorithm extends AbstractAlgorithm implements ISubject{
|
|||
|
|
|||
|
@Override
|
|||
|
protected ProcessDescriptionType initializeDescription() {
|
|||
|
ProcessDescriptionsDocument document = ProcessDescriptionsDocument.Factory.newInstance();
|
|||
|
ProcessDescriptions processDescriptions = document.addNewProcessDescriptions();
|
|||
|
ProcessDescriptionType processDescription = processDescriptions.addNewProcessDescription();
|
|||
|
processDescription.setStatusSupported(true);
|
|||
|
processDescription.setStoreSupported(true);
|
|||
|
processDescription.setProcessVersion("1.0.0");
|
|||
|
|
|||
|
//1. Identifier
|
|||
|
processDescription.addNewIdentifier().setStringValue(this.getClass().getName());
|
|||
|
processDescription.addNewTitle().setStringValue(this.getClass().getCanonicalName());
|
|||
|
|
|||
|
//2. Inputs
|
|||
|
List<String> identifiers = this.getInputIdentifiers();
|
|||
|
DataInputs dataInputs = null;
|
|||
|
if(identifiers.size()>0){
|
|||
|
dataInputs = processDescription.addNewDataInputs();
|
|||
|
}
|
|||
|
|
|||
|
for(String identifier : identifiers){
|
|||
|
InputDescriptionType dataInput = dataInputs.addNewInput();
|
|||
|
dataInput.setMinOccurs(getMinOccurs(identifier));
|
|||
|
dataInput.setMaxOccurs(getMaxOccurs(identifier));
|
|||
|
dataInput.addNewIdentifier().setStringValue(identifier);
|
|||
|
dataInput.addNewTitle().setStringValue(identifier);
|
|||
|
|
|||
|
Class<?> inputDataTypeClass = this.getInputDataType(identifier);
|
|||
|
Class<?>[] interfaces = inputDataTypeClass.getInterfaces();
|
|||
|
|
|||
|
//we have to add this because of the new AbstractLiteralDataBinding class
|
|||
|
if(interfaces.length == 0){
|
|||
|
interfaces = inputDataTypeClass.getSuperclass().getInterfaces();
|
|||
|
}
|
|||
|
|
|||
|
for(Class<?> implementedInterface : interfaces){
|
|||
|
if(implementedInterface.equals(ILiteralData.class)){
|
|||
|
LiteralInputType literalData = dataInput.addNewLiteralData();
|
|||
|
String inputClassType = "";
|
|||
|
|
|||
|
Constructor<?>[] constructors = inputDataTypeClass.getConstructors();
|
|||
|
for(Constructor<?> constructor : constructors){
|
|||
|
Class<?>[] parameters = constructor.getParameterTypes();
|
|||
|
if(parameters.length==1){
|
|||
|
inputClassType = parameters[0].getSimpleName();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if(inputClassType.length()>0){
|
|||
|
DomainMetadataType datatype = literalData.addNewDataType();
|
|||
|
datatype.setReference("xs:"+inputClassType.toLowerCase());
|
|||
|
literalData.addNewAnyValue();
|
|||
|
}
|
|||
|
}else if(implementedInterface.equals(IBBOXData.class)){
|
|||
|
SupportedCRSsType bboxData = dataInput.addNewBoundingBoxData();
|
|||
|
String[] supportedCRSAray = getSupportedCRSForBBOXInput(identifier);
|
|||
|
for(int i = 0; i<supportedCRSAray.length; i++){
|
|||
|
if(i==0){
|
|||
|
Default defaultCRS = bboxData.addNewDefault();
|
|||
|
defaultCRS.setCRS(supportedCRSAray[0]);
|
|||
|
if(supportedCRSAray.length==1){
|
|||
|
CRSsType supportedCRS = bboxData.addNewSupported();
|
|||
|
supportedCRS.addCRS(supportedCRSAray[0]);
|
|||
|
}
|
|||
|
}else{
|
|||
|
if(i==1){
|
|||
|
CRSsType supportedCRS = bboxData.addNewSupported();
|
|||
|
supportedCRS.addCRS(supportedCRSAray[1]);
|
|||
|
}else{
|
|||
|
bboxData.getSupported().addCRS(supportedCRSAray[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
}else if(implementedInterface.equals(IComplexData.class)){
|
|||
|
SupportedComplexDataInputType complexData = dataInput.addNewComplexData();
|
|||
|
List<IParser> parsers = ParserFactory.getInstance().getAllParsers();
|
|||
|
List<IParser> foundParsers = new ArrayList<IParser>();
|
|||
|
for(IParser parser : parsers) {
|
|||
|
Class<?>[] supportedClasses = parser.getSupportedDataBindings();
|
|||
|
for(Class<?> clazz : supportedClasses){
|
|||
|
if(clazz.equals(inputDataTypeClass)){
|
|||
|
foundParsers.add(parser);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
addInputFormats(complexData, foundParsers);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//3. Outputs
|
|||
|
ProcessOutputs dataOutputs = processDescription.addNewProcessOutputs();
|
|||
|
List<String> outputIdentifiers = this.getOutputIdentifiers();
|
|||
|
for(String identifier : outputIdentifiers){
|
|||
|
OutputDescriptionType dataOutput = dataOutputs.addNewOutput();
|
|||
|
|
|||
|
|
|||
|
dataOutput.addNewIdentifier().setStringValue(identifier);
|
|||
|
dataOutput.addNewTitle().setStringValue(identifier);
|
|||
|
dataOutput.addNewAbstract().setStringValue(identifier);
|
|||
|
|
|||
|
Class<?> outputDataTypeClass = this.getOutputDataType(identifier);
|
|||
|
Class<?>[] interfaces = outputDataTypeClass.getInterfaces();
|
|||
|
|
|||
|
//we have to add this because of the new AbstractLiteralDataBinding class
|
|||
|
if(interfaces.length == 0){
|
|||
|
interfaces = outputDataTypeClass.getSuperclass().getInterfaces();
|
|||
|
}
|
|||
|
for(Class<?> implementedInterface : interfaces){
|
|||
|
|
|||
|
|
|||
|
if(implementedInterface.equals(ILiteralData.class)){
|
|||
|
LiteralOutputType literalData = dataOutput.addNewLiteralOutput();
|
|||
|
String outputClassType = "";
|
|||
|
|
|||
|
Constructor<?>[] constructors = outputDataTypeClass.getConstructors();
|
|||
|
for(Constructor<?> constructor : constructors){
|
|||
|
Class<?>[] parameters = constructor.getParameterTypes();
|
|||
|
if(parameters.length==1){
|
|||
|
outputClassType = parameters[0].getSimpleName();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if(outputClassType.length()>0){
|
|||
|
literalData.addNewDataType().setReference("xs:"+outputClassType.toLowerCase());
|
|||
|
}
|
|||
|
|
|||
|
}else if(implementedInterface.equals(IBBOXData.class)){
|
|||
|
SupportedCRSsType bboxData = dataOutput.addNewBoundingBoxOutput();
|
|||
|
String[] supportedCRSAray = getSupportedCRSForBBOXOutput(identifier);
|
|||
|
for(int i = 0; i<supportedCRSAray.length; i++){
|
|||
|
if(i==0){
|
|||
|
Default defaultCRS = bboxData.addNewDefault();
|
|||
|
defaultCRS.setCRS(supportedCRSAray[0]);
|
|||
|
if(supportedCRSAray.length==1){
|
|||
|
CRSsType supportedCRS = bboxData.addNewSupported();
|
|||
|
supportedCRS.addCRS(supportedCRSAray[0]);
|
|||
|
}
|
|||
|
}else{
|
|||
|
if(i==1){
|
|||
|
CRSsType supportedCRS = bboxData.addNewSupported();
|
|||
|
supportedCRS.addCRS(supportedCRSAray[1]);
|
|||
|
}else{
|
|||
|
bboxData.getSupported().addCRS(supportedCRSAray[i]);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}else if(implementedInterface.equals(IComplexData.class)){
|
|||
|
|
|||
|
SupportedComplexDataType complexData = dataOutput.addNewComplexOutput();
|
|||
|
|
|||
|
List<IGenerator> generators = GeneratorFactory.getInstance().getAllGenerators();
|
|||
|
List<IGenerator> foundGenerators = new ArrayList<IGenerator>();
|
|||
|
for(IGenerator generator : generators) {
|
|||
|
Class<?>[] supportedClasses = generator.getSupportedDataBindings();
|
|||
|
for(Class<?> clazz : supportedClasses){
|
|||
|
if(clazz.equals(outputDataTypeClass)){
|
|||
|
foundGenerators.add(generator);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
addOutputFormats(complexData, foundGenerators);
|
|||
|
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
return document.getProcessDescriptions().getProcessDescriptionArray(0);
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Override this class for BBOX input data to set supported mime types. The first one in the resulting array will be the default one.
|
|||
|
* @param identifier ID of the input BBOXType
|
|||
|
* @return
|
|||
|
*/
|
|||
|
public String[] getSupportedCRSForBBOXInput(String identifier){
|
|||
|
return new String[0];
|
|||
|
}
|
|||
|
|
|||
|
/**
|
|||
|
* Override this class for BBOX output data to set supported mime types. The first one in the resulting array will be the default one.
|
|||
|
* @param identifier ID of the input BBOXType
|
|||
|
* @return
|
|||
|
*/
|
|||
|
public String[] getSupportedCRSForBBOXOutput(String identifier){
|
|||
|
return new String[0];
|
|||
|
}
|
|||
|
|
|||
|
public BigInteger getMinOccurs(String identifier){
|
|||
|
return new BigInteger("1");
|
|||
|
}
|
|||
|
public BigInteger getMaxOccurs(String identifier){
|
|||
|
return new BigInteger("1");
|
|||
|
}
|
|||
|
|
|||
|
public abstract List<String> getInputIdentifiers();
|
|||
|
public abstract List<String> getOutputIdentifiers();
|
|||
|
|
|||
|
|
|||
|
|
|||
|
private List<IObserver> observers = new ArrayList<IObserver>();
|
|||
|
|
|||
|
private Object state = null;
|
|||
|
|
|||
|
public Object getState() {
|
|||
|
return state;
|
|||
|
}
|
|||
|
|
|||
|
public void update(Object state) {
|
|||
|
this.state = state;
|
|||
|
notifyObservers();
|
|||
|
}
|
|||
|
|
|||
|
public void addObserver(IObserver o) {
|
|||
|
observers.add(o);
|
|||
|
}
|
|||
|
|
|||
|
public void removeObserver(IObserver o) {
|
|||
|
observers.remove(o);
|
|||
|
}
|
|||
|
|
|||
|
public void notifyObservers() {
|
|||
|
Iterator<IObserver> i = observers.iterator();
|
|||
|
while (i.hasNext()) {
|
|||
|
IObserver o = (IObserver) i.next();
|
|||
|
o.update(this);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
@Override
|
|||
|
public List<String> getErrors() {
|
|||
|
List<String> errors = new ArrayList<String>();
|
|||
|
return errors;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private void addInputFormats(SupportedComplexDataInputType complexData,
|
|||
|
List<IParser> foundParsers) {
|
|||
|
ComplexDataCombinationsType supportedInputFormat = complexData
|
|||
|
.addNewSupported();
|
|||
|
|
|||
|
for (int i = 0; i < foundParsers.size(); i++) {
|
|||
|
IParser parser = foundParsers.get(i);
|
|||
|
|
|||
|
Format[] supportedFullFormats = parser.getSupportedFullFormats();
|
|||
|
|
|||
|
if (complexData.getDefault() == null) {
|
|||
|
ComplexDataCombinationType defaultInputFormat = complexData
|
|||
|
.addNewDefault();
|
|||
|
/*
|
|||
|
* default format will be the first config format
|
|||
|
*/
|
|||
|
Format format = supportedFullFormats[0];
|
|||
|
ComplexDataDescriptionType defaultFormat = defaultInputFormat
|
|||
|
.addNewFormat();
|
|||
|
defaultFormat.setMimeType(format.getMimetype());
|
|||
|
|
|||
|
String encoding = format.getEncoding();
|
|||
|
|
|||
|
if (encoding != null && !encoding.equals("")) {
|
|||
|
defaultFormat.setEncoding(encoding);
|
|||
|
}
|
|||
|
|
|||
|
String schema = format.getSchema();
|
|||
|
|
|||
|
if (schema != null && !schema.equals("")) {
|
|||
|
defaultFormat.setSchema(schema);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
for (int j = 0; j < supportedFullFormats.length; j++) {
|
|||
|
/*
|
|||
|
* create supportedFormat for each mimetype, encoding, schema
|
|||
|
* composition mimetypes can have several encodings and schemas
|
|||
|
*/
|
|||
|
Format format1 = supportedFullFormats[j];
|
|||
|
|
|||
|
/*
|
|||
|
* add one format for this mimetype
|
|||
|
*/
|
|||
|
ComplexDataDescriptionType supportedFormat = supportedInputFormat
|
|||
|
.addNewFormat();
|
|||
|
supportedFormat.setMimeType(format1.getMimetype());
|
|||
|
if (format1.getEncoding() != null) {
|
|||
|
supportedFormat.setEncoding(format1.getEncoding());
|
|||
|
}
|
|||
|
if (format1.getSchema() != null) {
|
|||
|
supportedFormat.setSchema(format1.getSchema());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void addOutputFormats(SupportedComplexDataType complexData,
|
|||
|
List<IGenerator> foundGenerators) {
|
|||
|
ComplexDataCombinationsType supportedOutputFormat = complexData
|
|||
|
.addNewSupported();
|
|||
|
|
|||
|
for (int i = 0; i < foundGenerators.size(); i++) {
|
|||
|
IGenerator generator = foundGenerators.get(i);
|
|||
|
|
|||
|
Format[] supportedFullFormats = generator.getSupportedFullFormats();
|
|||
|
|
|||
|
if (complexData.getDefault() == null) {
|
|||
|
ComplexDataCombinationType defaultInputFormat = complexData
|
|||
|
.addNewDefault();
|
|||
|
/*
|
|||
|
* default format will be the first config format
|
|||
|
*/
|
|||
|
Format format = supportedFullFormats[0];
|
|||
|
ComplexDataDescriptionType defaultFormat = defaultInputFormat
|
|||
|
.addNewFormat();
|
|||
|
defaultFormat.setMimeType(format.getMimetype());
|
|||
|
|
|||
|
String encoding = format.getEncoding();
|
|||
|
|
|||
|
if (encoding != null && !encoding.equals("")) {
|
|||
|
defaultFormat.setEncoding(encoding);
|
|||
|
}
|
|||
|
|
|||
|
String schema = format.getSchema();
|
|||
|
|
|||
|
if (schema != null && !schema.equals("")) {
|
|||
|
defaultFormat.setSchema(schema);
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
for (int j = 0; j < supportedFullFormats.length; j++) {
|
|||
|
/*
|
|||
|
* create supportedFormat for each mimetype, encoding, schema
|
|||
|
* composition mimetypes can have several encodings and schemas
|
|||
|
*/
|
|||
|
Format format1 = supportedFullFormats[j];
|
|||
|
|
|||
|
/*
|
|||
|
* add one format for this mimetype
|
|||
|
*/
|
|||
|
ComplexDataDescriptionType supportedFormat = supportedOutputFormat
|
|||
|
.addNewFormat();
|
|||
|
supportedFormat.setMimeType(format1.getMimetype());
|
|||
|
if (format1.getEncoding() != null) {
|
|||
|
supportedFormat.setEncoding(format1.getEncoding());
|
|||
|
}
|
|||
|
if (format1.getSchema() != null) {
|
|||
|
supportedFormat.setSchema(format1.getSchema());
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
}
|