summaryrefslogtreecommitdiffstats
path: root/petascope/src/petascope/wcst/server/WcstServer.java
blob: fc2cb9e7677748ba99e25466e75ff17c2e6de9f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
/*
 * This file is part of rasdaman community.
 *
 * Rasdaman community is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Rasdaman community is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with rasdaman community.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Copyright 2003, 2004, 2005, 2006, 2007, 2008, 2009 Peter Baumann /
 rasdaman GmbH.
 *
 * For more information please see <http://www.rasdaman.org>
 * or contact Peter Baumann via <baumann@rasdaman.com>.
 */
package petascope.wcst.server;

//~--- non-JDK imports --------------------------------------------------------
import petascope.ConfigManager;
import net.opengis.ows.v_1_0_0.ExceptionReport;

import petascope.wcst.transaction.ServiceFirewall;
import petascope.wcst.transaction.executeAsyncTransaction;
import petascope.wcst.transaction.executeTransaction;
import wcst.transaction.schema.AcknowledgementType;
import wcst.transaction.schema.TransactionResponseType;
import wcst.transaction.schema.TransactionType;

//~--- JDK imports ------------------------------------------------------------

import java.io.StringReader;
import java.io.StringWriter;

import java.util.Date;
import java.util.GregorianCalendar;

import javax.xml.XMLConstants;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBElement;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.datatype.DatatypeConfigurationException;
import javax.xml.datatype.DatatypeFactory;
import javax.xml.datatype.XMLGregorianCalendar;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLOutputFactory;
import javax.xml.stream.XMLStreamWriter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import petascope.PetascopeXmlNamespaceMapper;
import petascope.wcps.server.core.DbMetadataSource;
import petascope.wcs.server.exceptions.InvalidPropertyValueException;
import petascope.wcs.server.exceptions.MaliciousQueryException;
import petascope.wcs.server.exceptions.WCSException;
import petascope.wcs.server.exceptions.XmlStructuresException;

/**
 * The Web Coverage Service, with the Transactional extension (WcstServer)
 *
 * @author Andrei Aiordachioaie
 */
public class WcstServer {

    private static Logger LOG = LoggerFactory.getLogger(WcstServer.class);
    private static Boolean finished;
    private boolean synchronous = true;
    private String responseHandler;
    private DbMetadataSource meta;

    /**
     * Public minimal constructor
     */
    public WcstServer(DbMetadataSource source) throws WCSException {
        finished = false;
        meta = source;

        /* Check user settings */
        String cfg = ConfigManager.WCST_DEFAULT_DATATYPE;
        if (source.getDataTypes().contains(cfg) == false) {
            throw new InvalidPropertyValueException("The following setting is not a valid datatype: " + cfg);
        }
        cfg = ConfigManager.WCST_DEFAULT_INTERPOLATION;
        if (source.getInterpolationTypes().contains(cfg) == false) {
            throw new InvalidPropertyValueException("The following setting is not a valid interpolation method: " + cfg);
        }
        cfg = ConfigManager.WCST_DEFAULT_NULL_RESISTANCE;
        if (source.getNullResistances().contains(cfg) == false) {
            throw new InvalidPropertyValueException("The following setting is not a valid null resistance: " + cfg);
        }
    }

    /**
     * Web service operation
     */
    public String Transaction(String stringXml) {
        // Actual contents of these two strings do not matter
        String output = "Default output. ";
        String errmsg = "No error. ";

        finished = false;
        try {
            try {
                // Check if Firewall allows the query
                if (ServiceFirewall.reject(stringXml)) {
                    throw new MaliciousQueryException("WCS-T Service Firewall "
                            + "refused to run possibly malitious query.");
                }

                // read the input XML
                LOG.debug("Reading the input XML file ... ");
                JAXBContext context = JAXBContext.newInstance(
                        TransactionType.class.getPackage().getName());
                Unmarshaller unmarshaller = context.createUnmarshaller();
                Object xml = unmarshaller.unmarshal(new StringReader(stringXml));

                if (xml instanceof JAXBElement) {
                    xml = ((JAXBElement) xml).getValue();
                }

                TransactionType input = (TransactionType) xml;

                /**
                 * We can work in both asynchronous and synchronous mode.
                 *
                 * If we are in async mode, we generate an acknowledgement that
                 * we have received the Transaction request. Next, when we finish processing,
                 * we send the output (as a String) to the specified responseHandler.
                 *
                 * In synchronous mode, we just do the processing and output
                 * the result.
                 */
                if (input.getResponseHandler() == null) {
                    synchronous = true;
                    responseHandler = null;
                } else {
                    synchronous = false;
                    responseHandler = input.getResponseHandler();
                }

                executeTransaction exec = new executeTransaction(input, meta);

                /** Synchronous operation */
                if (synchronous == true) {
                    TransactionResponseType response = exec.get();
                    JAXBElement jaxbOutput =
                            new JAXBElement(
                            new QName("http://www.opengis.net/wcs/1.1/wcst",
                            "TransactionResponse", XMLConstants.DEFAULT_NS_PREFIX),
                            TransactionResponseType.class, response);

                    // Write the output xml to a string
                    LOG.debug("Marshalling with context: " + response.getClass().getPackage().getName());
                    final StringWriter writer = new StringWriter();
                    try {
                        context = JAXBContext.newInstance(response.getClass());
                        final XMLStreamWriter xmlStreamWriter = XMLOutputFactory.newInstance().createXMLStreamWriter(writer);

                        final Marshaller marshaller = context.createMarshaller();
                        marshaller.setProperty("com.sun.xml.bind.namespacePrefixMapper", new PetascopeXmlNamespaceMapper());
                        marshaller.setProperty("jaxb.formatted.output", true);
                        marshaller.setProperty("jaxb.schemaLocation", "http://www.opengis.net/wcs/1.1/wcst http://schemas.opengis.net/wcst/ "
                                + "http://www.opengis.net/ows/1.1 http://schemas.opengis.net/ows/1.0.0/owsExceptionReport.xsd");
                        marshaller.marshal(jaxbOutput, xmlStreamWriter);
                    } catch (final Exception e) {
                        throw new RuntimeException(e.getMessage(), e);
                    }
                    output = writer.toString();
                    LOG.debug("Done! User has the TransactionResponse result !");
                } else /** Asynchronous operation */
                {
                    /* (1) Create acknowledgement that we received the request */
                    AcknowledgementType ack = new AcknowledgementType();
                    GregorianCalendar c = new GregorianCalendar();

                    c.setTime(new Date());
                    XMLGregorianCalendar date2 = DatatypeFactory.newInstance().newXMLGregorianCalendar(c);

                    ack.setTimeStamp(date2);
                    ack.setOperationRequest(input);
                    ack.setRequestId(exec.generateRequestId());
                    JAXBElement jaxbOutput = new JAXBElement(new QName("", "Acknowledgement"),
                            TransactionResponseType.class, ack);

                    /* (2) Write the acknowledgement to a string */
                    JAXBContext jaxbCtx = JAXBContext.newInstance(
                            ack.getClass().getPackage().getName());
                    Marshaller marshaller = jaxbCtx.createMarshaller();

                    marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                    marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                    StringWriter strWriter = new StringWriter();

                    marshaller.marshal(jaxbOutput, strWriter);
                    output = strWriter.toString();
                    LOG.debug("Created the acknowledgement of the request !");
                    LOG.debug("Now starting to asynchronously execute the transaction...");

                    /* (3) Start asynchronous processing */
                    executeAsyncTransaction execAsync = new executeAsyncTransaction(exec,
                            responseHandler);

                    execAsync.start();
                }
                finished = true;

            } catch (JAXBException e) {
                throw new XmlStructuresException("Could not marshall/unmarshall XML structures.", e);
            } catch (DatatypeConfigurationException e) {
                throw new XmlStructuresException("Could not build request acknowledgement. ", e);
            }
        } catch (WCSException e) {
            LOG.info("Caught WCST Exception");
            ExceptionReport report = e.getReport();

            try {
                JAXBContext jaxbCtx = JAXBContext.newInstance(
                        report.getClass().getPackage().getName());
                Marshaller marshaller = jaxbCtx.createMarshaller();

                marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
                marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
                StringWriter strWriter = new StringWriter();

                marshaller.marshal(report, strWriter);
                output = strWriter.toString();
                finished = true;
                LOG.error("WCS-T Exception: " + e.getErrorCode() + ", with message '"
                        + e.getErrorDetail() + "'");
                LOG.debug("Done with the Error Report !");
            } catch (JAXBException e2) {
                errmsg = e2.getMessage();
                LOG.error("Could not build XML error report. Stack trace: " + e2);
            }
        }

        if (finished == false) {
            output = errmsg;
        }

        return output;
    }
}