Project

General

Profile

1 6253 leinfelder
/**
2
 *  '$RCSfile$'
3
 *  Copyright: 2011 Regents of the University of California and the
4
 *              National Center for Ecological Analysis and Synthesis
5
 *
6
 *   '$Author$'
7
 *     '$Date$'
8
 *
9
 * This program is free software; you can redistribute it and/or modify
10
 * it under the terms of the GNU General Public License as published by
11
 * the Free Software Foundation; either version 2 of the License, or
12
 * (at your option) any later version.
13
 *
14
 * This program is distributed in the hope that it will be useful,
15
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17
 * GNU General Public License for more details.
18
 *
19
 * You should have received a copy of the GNU General Public License
20
 * along with this program; if not, write to the Free Software
21
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22
 */
23
package edu.ucsb.nceas.metacat.restservice;
24
25
import java.io.File;
26
import java.io.FileInputStream;
27
import java.io.IOException;
28
import java.io.InputStream;
29
import java.io.OutputStream;
30
import java.util.Date;
31 6622 leinfelder
import java.util.Enumeration;
32 6253 leinfelder
import java.util.Map;
33
34
import javax.servlet.ServletContext;
35
import javax.servlet.http.HttpServletRequest;
36
import javax.servlet.http.HttpServletResponse;
37 6514 leinfelder
import javax.xml.parsers.ParserConfigurationException;
38 6253 leinfelder
39 6269 leinfelder
import org.apache.commons.fileupload.FileUploadException;
40 6253 leinfelder
import org.apache.commons.io.IOUtils;
41
import org.apache.log4j.Logger;
42
import org.dataone.client.ObjectFormatCache;
43
import org.dataone.service.exceptions.BaseException;
44
import org.dataone.service.exceptions.IdentifierNotUnique;
45
import org.dataone.service.exceptions.InsufficientResources;
46
import org.dataone.service.exceptions.InvalidRequest;
47
import org.dataone.service.exceptions.InvalidSystemMetadata;
48
import org.dataone.service.exceptions.InvalidToken;
49
import org.dataone.service.exceptions.NotAuthorized;
50
import org.dataone.service.exceptions.NotFound;
51
import org.dataone.service.exceptions.NotImplemented;
52
import org.dataone.service.exceptions.ServiceFailure;
53
import org.dataone.service.exceptions.UnsupportedType;
54 6869 cjones
import org.dataone.service.exceptions.VersionMismatch;
55 6366 leinfelder
import org.dataone.service.types.v1.AccessPolicy;
56
import org.dataone.service.types.v1.Checksum;
57 6803 leinfelder
import org.dataone.service.types.v1.ChecksumAlgorithmList;
58
import org.dataone.service.types.v1.DescribeResponse;
59 6366 leinfelder
import org.dataone.service.types.v1.Event;
60
import org.dataone.service.types.v1.Identifier;
61
import org.dataone.service.types.v1.Log;
62 6592 cjones
import org.dataone.service.types.v1.NodeReference;
63 6366 leinfelder
import org.dataone.service.types.v1.ObjectFormat;
64
import org.dataone.service.types.v1.ObjectFormatIdentifier;
65
import org.dataone.service.types.v1.ObjectFormatList;
66 6622 leinfelder
import org.dataone.service.types.v1.ObjectList;
67 6366 leinfelder
import org.dataone.service.types.v1.ObjectLocationList;
68
import org.dataone.service.types.v1.Permission;
69 6592 cjones
import org.dataone.service.types.v1.Replica;
70
import org.dataone.service.types.v1.ReplicationPolicy;
71
import org.dataone.service.types.v1.ReplicationStatus;
72 6366 leinfelder
import org.dataone.service.types.v1.Subject;
73
import org.dataone.service.types.v1.SystemMetadata;
74 6803 leinfelder
import org.dataone.service.util.Constants;
75 6469 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
76 7048 leinfelder
import org.dataone.service.util.EncodingUtilities;
77 6367 leinfelder
import org.dataone.service.util.TypeMarshaller;
78 6253 leinfelder
import org.jibx.runtime.JiBXException;
79 6514 leinfelder
import org.xml.sax.SAXException;
80 6253 leinfelder
81
import edu.ucsb.nceas.metacat.dataone.CNodeService;
82 6639 leinfelder
import edu.ucsb.nceas.metacat.properties.PropertyService;
83
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
84 6253 leinfelder
85
/**
86
 * CN REST service implementation handler
87
 *
88 6756 cjones
 * ****************** CNCore -- DONE create() - POST /d1/cn/object/PID
89
 * listFormats() - GET /d1/cn/formats getFormat() - GET /d1/cn/formats/FMTID
90
 * getLogRecords - GET /d1/cn/log reserveIdentifier() - POST /d1/cn/reserve
91
 * listNodes() - Not implemented registerSystemMetadata() - POST /d1/meta/PID
92
 *
93
 * CNRead -- DONE get() - GET /d1/cn/object/PID getSystemMetadata() - GET
94
 * /d1/cn/meta/PID resolve() - GET /d1/cn/resolve/PID assertRelation() - GET
95
 * /d1/cn/assertRelation/PID getChecksum() - GET /d1/cn/checksum search() - Not
96
 * implemented in Metacat
97
 *
98
 * CNAuthorization setOwner() - PUT /d1/cn/owner/PID isAuthorized() - GET
99
 * /d1/cn/isAuthorized/PID setAccessPolicy() - POST /d1/cn/accessRules
100
 *
101
 * CNIdentity - not implemented at all on Metacat
102
 *
103
 * CNReplication setReplicationStatus() - PUT /replicaNotifications/PID
104
 * updateReplicationMetadata() - PUT /replicaMetadata/PID setReplicationPolicy()
105
 * - PUT /replicaPolicies/PID isNodeAuthorized() - GET
106
 * /replicaAuthorizations/PID
107
 *
108
 * CNRegister -- not implemented at all in Metacat ******************
109
 *
110 6253 leinfelder
 * @author leinfelder
111 6756 cjones
 *
112 6253 leinfelder
 */
113 6267 leinfelder
public class CNResourceHandler extends D1ResourceHandler {
114 6253 leinfelder
115 6756 cjones
    /** CN-specific operations **/
116 6253 leinfelder
    protected static final String RESOURCE_RESERVE = "reserve";
117 6271 leinfelder
    protected static final String RESOURCE_FORMATS = "formats";
118 6253 leinfelder
    protected static final String RESOURCE_RESOLVE = "resolve";
119
    protected static final String RESOURCE_OWNER = "owner";
120 6592 cjones
    protected static final String RESOURCE_REPLICATION_POLICY = "replicaPolicies";
121
    protected static final String RESOURCE_REPLICATION_META = "replicaMetadata";
122
    protected static final String RESOURCE_REPLICATION_AUTHORIZED = "replicaAuthorizations";
123
    protected static final String RESOURCE_REPLICATION_NOTIFY = "replicaNotifications";
124 6756 cjones
125 6253 leinfelder
    public CNResourceHandler(ServletContext servletContext,
126 6756 cjones
            HttpServletRequest request, HttpServletResponse response) {
127
        super(servletContext, request, response);
128 6253 leinfelder
        logMetacat = Logger.getLogger(CNResourceHandler.class);
129 6756 cjones
    }
130 6253 leinfelder
131 6756 cjones
    /**
132
     * This function is called from REST API servlet and handles each request to
133
     * the servlet
134 6253 leinfelder
     *
135 6756 cjones
     * @param httpVerb
136
     *            (GET, POST, PUT or DELETE)
137 6253 leinfelder
     */
138 6271 leinfelder
    @Override
139 6253 leinfelder
    public void handle(byte httpVerb) {
140 6756 cjones
        // prepare the handler
141
        super.handle(httpVerb);
142
143 6253 leinfelder
        try {
144 6282 leinfelder
145 6994 leinfelder
        	// only service requests if we have D1 configured
146
        	if (!isD1Enabled()) {
147
        		ServiceFailure se = new ServiceFailure("0000", "DataONE services are not enabled on this node");
148
                serializeException(se, response.getOutputStream());
149
                return;
150
        	}
151
152 6756 cjones
            // get the resource
153 6282 leinfelder
            String resource = request.getPathInfo();
154
            resource = resource.substring(resource.indexOf("/") + 1);
155 6756 cjones
156 6396 leinfelder
            // for the rest of the resouce
157 6282 leinfelder
            String extra = null;
158 6756 cjones
159
            logMetacat.debug("handling verb " + httpVerb
160
                    + " request with resource '" + resource + "'");
161 6253 leinfelder
            boolean status = false;
162 6271 leinfelder
163 6253 leinfelder
            if (resource != null) {
164
165 6756 cjones
                if (resource.startsWith(RESOURCE_ACCESS_RULES)
166
                        && httpVerb == PUT) {
167 6253 leinfelder
                    logMetacat.debug("Setting access policy");
168 6514 leinfelder
                    // after the command
169
                    extra = parseTrailing(resource, RESOURCE_ACCESS_RULES);
170
                    setAccess(extra);
171 6253 leinfelder
                    status = true;
172
                    logMetacat.debug("done setting access");
173 6756 cjones
174 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_META)) {
175 6253 leinfelder
                    logMetacat.debug("Using resource: " + RESOURCE_META);
176 6756 cjones
177 6396 leinfelder
                    // after the command
178
                    extra = parseTrailing(resource, RESOURCE_META);
179 6756 cjones
180 6253 leinfelder
                    // get
181
                    if (httpVerb == GET) {
182 6282 leinfelder
                        getSystemMetadataObject(extra);
183 6253 leinfelder
                        status = true;
184
                    }
185
                    // post to register system metadata
186
                    if (httpVerb == POST) {
187 6974 leinfelder
                        registerSystemMetadata();
188 6756 cjones
                        status = true;
189 6253 leinfelder
                    }
190
191 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
192 6253 leinfelder
                    // reserve the ID (in params)
193
                    if (httpVerb == POST) {
194 6756 cjones
                        reserve();
195
                        status = true;
196 6253 leinfelder
                    }
197 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
198 6756 cjones
199
                    // after the command
200 6396 leinfelder
                    extra = parseTrailing(resource, RESOURCE_RESOLVE);
201 6756 cjones
202 6253 leinfelder
                    // resolve the object location
203
                    if (httpVerb == GET) {
204 6756 cjones
                        resolve(extra);
205
                        status = true;
206 6253 leinfelder
                    }
207 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_OWNER)) {
208 6756 cjones
209
                    // after the command
210 6396 leinfelder
                    extra = parseTrailing(resource, RESOURCE_OWNER);
211 6756 cjones
212 6253 leinfelder
                    // set the owner
213
                    if (httpVerb == PUT) {
214 6756 cjones
                        owner(extra);
215
                        status = true;
216
                    }
217 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
218 6756 cjones
219
                    // after the command
220 6396 leinfelder
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
221 6756 cjones
222 6253 leinfelder
                    // authorized?
223
                    if (httpVerb == GET) {
224 6756 cjones
                        isAuthorized(extra);
225
                        status = true;
226
                    }
227 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
228 6253 leinfelder
                    logMetacat.debug("Using resource 'object'");
229 6756 cjones
                    logMetacat
230
                            .debug("D1 Rest: Starting resource processing...");
231
232 6396 leinfelder
                    // after the command
233
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
234 6756 cjones
235 6282 leinfelder
                    logMetacat.debug("objectId: " + extra);
236 6253 leinfelder
                    logMetacat.debug("verb:" + httpVerb);
237
238
                    if (httpVerb == GET) {
239 6756 cjones
                        if (extra != null) {
240
                            getObject(extra);
241
                        } else {
242
                            listObjects();
243
                        }
244 6253 leinfelder
                        status = true;
245
                    } else if (httpVerb == POST) {
246 6973 leinfelder
                        putObject(FUNCTION_NAME_INSERT);
247 6253 leinfelder
                        status = true;
248 6803 leinfelder
                    } else if (httpVerb == HEAD) {
249
                        describeObject(extra);
250
                        status = true;
251 7077 leinfelder
                    } else if (httpVerb == DELETE) {
252
                        deleteObject(extra);
253
                        status = true;
254
                    }
255 6756 cjones
256 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
257 6756 cjones
                    logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
258
259
                    // after the command
260
                    extra = parseTrailing(resource, RESOURCE_FORMATS);
261
262
                    // handle each verb
263
                    if (httpVerb == GET) {
264
                        if (extra == null) {
265
                            // list the formats collection
266
                            listFormats();
267
                        } else {
268
                            // get the specified format
269
                            getFormat(extra);
270
                        }
271
                        status = true;
272
                    }
273
274 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_LOG)) {
275 6253 leinfelder
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
276 6756 cjones
                    // handle log events
277 6253 leinfelder
                    if (httpVerb == GET) {
278
                        getLog();
279
                        status = true;
280
                    }
281
282 7019 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_CHECKSUM)) {
283
                    logMetacat.debug("Using resource: " + Constants.RESOURCE_CHECKSUM);
284 6756 cjones
285 6396 leinfelder
                    // after the command
286 7019 leinfelder
                    extra = parseTrailing(resource, Constants.RESOURCE_CHECKSUM);
287 6756 cjones
288
                    // handle checksum requests
289 6253 leinfelder
                    if (httpVerb == GET) {
290 6756 cjones
291 7019 leinfelder
                    	if (extra != null && extra.length() > 0) {
292
	                        checksum(extra);
293
	                        status = true;
294
                    	} else {
295
                    		listChecksumAlgorithms();
296
                    		status = true;
297
                    	}
298 6756 cjones
299 6253 leinfelder
                    }
300 6756 cjones
301
                } else if (resource.startsWith(RESOURCE_REPLICATION_POLICY)
302
                        && httpVerb == PUT) {
303
304
                    logMetacat.debug("Using resource: "
305
                            + RESOURCE_REPLICATION_POLICY);
306 6592 cjones
                    // get the trailing pid
307
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_POLICY);
308
                    setReplicationPolicy(extra);
309
                    status = true;
310
311 6756 cjones
                } else if (resource.startsWith(RESOURCE_REPLICATION_META)
312
                        && httpVerb == PUT) {
313
314
                    logMetacat.debug("Using resource: "
315
                            + RESOURCE_REPLICATION_META);
316 6592 cjones
                    // get the trailing pid
317
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_META);
318
                    updateReplicationMetadata(extra);
319
                    status = true;
320
321 6756 cjones
                } else if (resource.startsWith(RESOURCE_REPLICATION_NOTIFY)
322
                        && httpVerb == PUT) {
323
324
                    logMetacat.debug("Using resource: "
325
                            + RESOURCE_REPLICATION_NOTIFY);
326 6592 cjones
                    // get the trailing pid
327
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_NOTIFY);
328
                    setReplicationStatus(extra);
329
                    status = true;
330 6756 cjones
331
                } else if (resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
332 6592 cjones
                        && httpVerb == GET) {
333 6756 cjones
334
                    logMetacat.debug("Using resource: "
335
                            + RESOURCE_REPLICATION_AUTHORIZED);
336 6592 cjones
                    // get the trailing pid
337 6756 cjones
                    extra = parseTrailing(resource,
338
                            RESOURCE_REPLICATION_AUTHORIZED);
339 6592 cjones
                    isNodeAuthorized(extra);
340
                    status = true;
341 6756 cjones
342 6803 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_MONITOR_PING)) {
343
                    if (httpVerb == GET) {
344
                    	// after the command
345
                        extra = parseTrailing(resource, Constants.RESOURCE_MONITOR_PING);
346
347
                        logMetacat.debug("processing ping request");
348
                        Date result = CNodeService.getInstance(request).ping();
349
                        // TODO: send to output
350
                        status = true;
351
                    }
352 6890 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_META_OBSOLETEDBY)
353
                        && httpVerb == PUT) {
354
355
                    logMetacat.debug("Using resource: "
356
                            + Constants.RESOURCE_META_OBSOLETEDBY);
357
                    // get the trailing pid
358
                    extra = parseTrailing(resource, Constants.RESOURCE_META_OBSOLETEDBY);
359
                    setObsoletedBy(extra);
360
                    status = true;
361 6891 leinfelder
                } else if (resource.startsWith(Constants.RESOURCE_REPLICATION_DELETE_REPLICA)
362
                        && httpVerb == PUT) {
363 6890 leinfelder
364 6891 leinfelder
                    logMetacat.debug("Using resource: "
365
                            + Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
366
                    // get the trailing pid
367
                    extra = parseTrailing(resource, Constants.RESOURCE_REPLICATION_DELETE_REPLICA);
368 7026 leinfelder
                    deleteReplica(extra);
369 6891 leinfelder
                    status = true;
370 6756 cjones
                }
371
372 6253 leinfelder
                if (!status) {
373 6756 cjones
                    throw new ServiceFailure("0000", "Unknown error, status = "
374
                            + status);
375 6253 leinfelder
                }
376
            } else {
377 6756 cjones
                throw new InvalidRequest("0000", "No resource matched for "
378
                        + resource);
379 6253 leinfelder
            }
380
        } catch (BaseException be) {
381 6756 cjones
            // report Exceptions as clearly and generically as possible
382
            OutputStream out = null;
383
            try {
384
                out = response.getOutputStream();
385
            } catch (IOException ioe) {
386
                logMetacat.error("Could not get output stream from response",
387
                        ioe);
388
            }
389 6253 leinfelder
            serializeException(be, out);
390
        } catch (Exception e) {
391 6270 leinfelder
            // report Exceptions as clearly and generically as possible
392 6253 leinfelder
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
393 6756 cjones
            OutputStream out = null;
394
            try {
395
                out = response.getOutputStream();
396
            } catch (IOException ioe) {
397
                logMetacat.error("Could not get output stream from response",
398
                        ioe);
399
            }
400
            ServiceFailure se = new ServiceFailure("0000", e.getMessage());
401 6270 leinfelder
            serializeException(se, out);
402 6253 leinfelder
        }
403
    }
404 6756 cjones
405 6270 leinfelder
    /**
406
     * Get the checksum for the given guid
407
     *
408
     * @param guid
409 6756 cjones
     * @throws NotImplemented
410
     * @throws InvalidRequest
411
     * @throws NotFound
412
     * @throws NotAuthorized
413
     * @throws ServiceFailure
414
     * @throws InvalidToken
415
     * @throws IOException
416
     * @throws JiBXException
417 6270 leinfelder
     */
418 6756 cjones
    private void checksum(String guid) throws InvalidToken, ServiceFailure,
419
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
420
            JiBXException, IOException {
421
        Identifier guidid = new Identifier();
422 6270 leinfelder
        guidid.setValue(guid);
423
        logMetacat.debug("getting checksum for object " + guid);
424 6756 cjones
        Checksum c = CNodeService.getInstance(request).getChecksum(session,
425
                guidid);
426 6270 leinfelder
        logMetacat.debug("got checksum " + c.getValue());
427
        response.setStatus(200);
428
        logMetacat.debug("serializing response");
429 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
430 6270 leinfelder
        logMetacat.debug("done serializing response.");
431 6756 cjones
432 6270 leinfelder
    }
433 6756 cjones
434
    /**
435
     * get the logs based on passed params. Available params are token,
436
     * fromDate, toDate, event. See
437
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud
438
     * .html#MN_crud.getLogRecords for more info
439
     *
440
     * @throws NotImplemented
441
     * @throws InvalidRequest
442
     * @throws NotAuthorized
443
     * @throws ServiceFailure
444
     * @throws InvalidToken
445
     * @throws IOException
446
     * @throws JiBXException
447 6253 leinfelder
     */
448 6756 cjones
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized,
449
            InvalidRequest, NotImplemented, IOException, JiBXException {
450
451 6270 leinfelder
        Date fromDate = null;
452
        Date toDate = null;
453
        Event event = null;
454
        Integer start = null;
455
        Integer count = null;
456 7099 leinfelder
        String pidFilter = null;
457 6756 cjones
458 6270 leinfelder
        try {
459 6756 cjones
            String fromDateS = params.get("fromDate")[0];
460 6272 leinfelder
            logMetacat.debug("param fromDateS: " + fromDateS);
461 6469 leinfelder
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
462 6270 leinfelder
        } catch (Exception e) {
463 6756 cjones
            logMetacat.warn("Could not parse fromDate: " + e.getMessage());
464 6253 leinfelder
        }
465 6270 leinfelder
        try {
466 6756 cjones
            String toDateS = params.get("toDate")[0];
467 6272 leinfelder
            logMetacat.debug("param toDateS: " + toDateS);
468 6469 leinfelder
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
469 6270 leinfelder
        } catch (Exception e) {
470 6756 cjones
            logMetacat.warn("Could not parse toDate: " + e.getMessage());
471
        }
472 6270 leinfelder
        try {
473 6756 cjones
            String eventS = params.get("event")[0];
474 6270 leinfelder
            event = Event.convert(eventS);
475
        } catch (Exception e) {
476 6756 cjones
            logMetacat.warn("Could not parse event: " + e.getMessage());
477
        }
478 6272 leinfelder
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
479 6756 cjones
480 6270 leinfelder
        try {
481 6756 cjones
            start = Integer.parseInt(params.get("start")[0]);
482 6270 leinfelder
        } catch (Exception e) {
483 6756 cjones
            logMetacat.warn("Could not parse start: " + e.getMessage());
484
        }
485 6270 leinfelder
        try {
486 6756 cjones
            count = Integer.parseInt(params.get("count")[0]);
487 6270 leinfelder
        } catch (Exception e) {
488 6756 cjones
            logMetacat.warn("Could not parse count: " + e.getMessage());
489
        }
490
491 7099 leinfelder
        try {
492
            pidFilter = params.get("pidFilter")[0];
493
        } catch (Exception e) {
494
            logMetacat.warn("Could not parse pidFilter: " + e.getMessage());
495
        }
496
497 6272 leinfelder
        logMetacat.debug("calling getLogRecords");
498 6756 cjones
        Log log = CNodeService.getInstance(request).getLogRecords(session,
499 7101 leinfelder
                fromDate, toDate, event, pidFilter, start, count);
500 6756 cjones
501 6270 leinfelder
        OutputStream out = response.getOutputStream();
502
        response.setStatus(200);
503
        response.setContentType("text/xml");
504 6756 cjones
505 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(log, out);
506 6756 cjones
507 6253 leinfelder
    }
508
509
    /**
510
     * Implements REST version of DataONE CRUD API --> get
511 6756 cjones
     *
512
     * @param guid
513
     *            ID of data object to be read
514
     * @throws NotImplemented
515
     * @throws InvalidRequest
516
     * @throws NotFound
517
     * @throws NotAuthorized
518
     * @throws ServiceFailure
519
     * @throws InvalidToken
520
     * @throws IOException
521 6253 leinfelder
     */
522 6756 cjones
    protected void getObject(String guid) throws InvalidToken, ServiceFailure,
523
            NotAuthorized, NotFound, InvalidRequest, NotImplemented,
524
            IOException {
525 6270 leinfelder
526 6280 leinfelder
        Identifier id = new Identifier();
527
        id.setValue(guid);
528 6756 cjones
529
        SystemMetadata sm = CNodeService.getInstance(request)
530
                .getSystemMetadata(session, id);
531
532
        // set the content type
533
        if (sm.getFormatId()
534
                .getValue()
535
                .trim()
536
                .equals(ObjectFormatCache.getInstance().getFormat("text/csv")
537
                        .getFormatId().getValue())) {
538 6280 leinfelder
            response.setContentType("text/csv");
539 6756 cjones
            response.setHeader("Content-Disposition",
540
                    "inline; filename=" + id.getValue() + ".csv");
541
        } else if (sm
542
                .getFormatId()
543
                .getValue()
544
                .trim()
545
                .equals(ObjectFormatCache.getInstance().getFormat("text/plain")
546
                        .getFormatId().getValue())) {
547 6280 leinfelder
            response.setContentType("text/plain");
548 6756 cjones
            response.setHeader("Content-Disposition",
549
                    "inline; filename=" + id.getValue() + ".txt");
550
        } else if (sm
551
                .getFormatId()
552
                .getValue()
553
                .trim()
554
                .equals(ObjectFormatCache.getInstance()
555
                        .getFormat("application/octet-stream").getFormatId()
556
                        .getValue())) {
557 6280 leinfelder
            response.setContentType("application/octet-stream");
558 6756 cjones
        } else {
559 6280 leinfelder
            response.setContentType("text/xml");
560 6756 cjones
            response.setHeader("Content-Disposition",
561
                    "inline; filename=" + id.getValue() + ".xml");
562 6280 leinfelder
        }
563 6756 cjones
564 6542 leinfelder
        InputStream data = CNodeService.getInstance(request).get(session, id);
565 6756 cjones
566 6280 leinfelder
        OutputStream out = response.getOutputStream();
567
        response.setStatus(200);
568
        IOUtils.copyLarge(data, out);
569 6756 cjones
570 6253 leinfelder
    }
571
572
    /**
573
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
574 6756 cjones
     *
575
     * @param guid
576
     *            ID of data object to be read
577
     * @throws NotImplemented
578
     * @throws InvalidRequest
579
     * @throws NotFound
580
     * @throws NotAuthorized
581
     * @throws ServiceFailure
582
     * @throws InvalidToken
583
     * @throws IOException
584
     * @throws JiBXException
585 6253 leinfelder
     */
586 6756 cjones
    protected void getSystemMetadataObject(String guid) throws InvalidToken,
587
            ServiceFailure, NotAuthorized, NotFound, InvalidRequest,
588
            NotImplemented, IOException, JiBXException {
589 6270 leinfelder
590
        Identifier id = new Identifier();
591
        id.setValue(guid);
592 6756 cjones
        SystemMetadata sysmeta = CNodeService.getInstance(request)
593
                .getSystemMetadata(session, id);
594
595 6270 leinfelder
        response.setContentType("text/xml");
596
        response.setStatus(200);
597
        OutputStream out = response.getOutputStream();
598 6756 cjones
599 6270 leinfelder
        // Serialize and write it to the output stream
600 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
601 6756 cjones
    }
602
603 6253 leinfelder
    /**
604 6756 cjones
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler >
605
     * handleInsertOrUpdateAction
606 6253 leinfelder
     *
607 6756 cjones
     * @param guid
608
     *            - ID of data object to be inserted or updated. If action is
609
     *            update, the pid is the existing pid. If insert, the pid is the
610
     *            new one
611
     * @throws InvalidRequest
612
     * @throws ServiceFailure
613
     * @throws IdentifierNotUnique
614
     * @throws JiBXException
615
     * @throws NotImplemented
616
     * @throws InvalidSystemMetadata
617
     * @throws InsufficientResources
618
     * @throws UnsupportedType
619
     * @throws NotAuthorized
620
     * @throws InvalidToken
621
     * @throws IOException
622
     * @throws IllegalAccessException
623
     * @throws InstantiationException
624 6253 leinfelder
     */
625 6973 leinfelder
    protected void putObject(String action) throws ServiceFailure,
626 6756 cjones
            InvalidRequest, IdentifierNotUnique, JiBXException, InvalidToken,
627
            NotAuthorized, UnsupportedType, InsufficientResources,
628
            InvalidSystemMetadata, NotImplemented, IOException,
629
            InstantiationException, IllegalAccessException {
630 6973 leinfelder
631 6269 leinfelder
        // Read the incoming data from its Mime Multipart encoding
632 6756 cjones
        Map<String, File> files = collectMultipartFiles();
633 6973 leinfelder
634 6974 leinfelder
	    // get the encoded pid string from the body and make the object
635 6975 leinfelder
        String pidString = multipartparams.get("pid").get(0);
636
        Identifier pid = new Identifier();
637
        pid.setValue(pidString);
638 6973 leinfelder
639
        logMetacat.debug("putObject: " + pid.getValue() + "/" + action);
640
641 6269 leinfelder
        InputStream object = null;
642
        InputStream sysmeta = null;
643 6253 leinfelder
644 6269 leinfelder
        File smFile = files.get("sysmeta");
645
        sysmeta = new FileInputStream(smFile);
646
        File objFile = files.get("object");
647
        object = new FileInputStream(objFile);
648 6253 leinfelder
649 6756 cjones
        if (action.equals(FUNCTION_NAME_INSERT)) { // handle inserts
650
651 6269 leinfelder
            logMetacat.debug("Commence creation...");
652 6756 cjones
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(
653
                    SystemMetadata.class, sysmeta);
654 6253 leinfelder
655 6973 leinfelder
656
            logMetacat.debug("creating object with pid " + pid.getValue());
657
            Identifier rId = CNodeService.getInstance(request).create(session, pid, object, smd);
658 6756 cjones
659 6269 leinfelder
            OutputStream out = response.getOutputStream();
660
            response.setStatus(200);
661
            response.setContentType("text/xml");
662 6756 cjones
663 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
664 6756 cjones
665 6269 leinfelder
        } else {
666
            throw new InvalidRequest("1000", "Operation must be create.");
667 6253 leinfelder
        }
668
    }
669
670
    /**
671
     * List the object formats registered with the system
672 6756 cjones
     *
673
     * @throws NotImplemented
674
     * @throws InsufficientResources
675
     * @throws NotFound
676
     * @throws ServiceFailure
677
     * @throws InvalidRequest
678
     * @throws IOException
679
     * @throws JiBXException
680 6253 leinfelder
     */
681 6756 cjones
    private void listFormats() throws InvalidRequest, ServiceFailure, NotFound,
682
            InsufficientResources, NotImplemented, IOException, JiBXException {
683
        logMetacat.debug("Entering listFormats()");
684 6270 leinfelder
685 6756 cjones
        ObjectFormatList objectFormatList = CNodeService.getInstance(request)
686
                .listFormats();
687
        // get the response output stream
688
        OutputStream out = response.getOutputStream();
689
        response.setStatus(200);
690
        response.setContentType("text/xml");
691
692
        // style the object with a processing directive
693
        String stylesheet = null;
694
        try {
695
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
696
        } catch (PropertyNotFoundException e) {
697
            logMetacat.warn("Could not locate DataONE types XSLT: "
698
                    + e.getMessage());
699
        }
700
701
        TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out,
702
                stylesheet);
703
704 6253 leinfelder
    }
705 6803 leinfelder
706
    private void listChecksumAlgorithms() throws IOException, ServiceFailure,
707
			NotImplemented, JiBXException {
708
		logMetacat.debug("Entering listFormats()");
709 6253 leinfelder
710 6803 leinfelder
		ChecksumAlgorithmList result = CNodeService.getInstance(request).listChecksumAlgorithms();
711
712
		// get the response output stream
713
		OutputStream out = response.getOutputStream();
714
		response.setStatus(200);
715
		response.setContentType("text/xml");
716
717 7034 leinfelder
		TypeMarshaller.marshalTypeToOutputStream(result, out);
718 6803 leinfelder
719
	}
720
721 6756 cjones
    /**
722 6803 leinfelder
     * http://mule1.dataone.org/ArchitectureDocs-current/apis/CN_APIs.html#CNRead.describe
723
     * @param pid
724
     * @throws InvalidToken
725
     * @throws ServiceFailure
726
     * @throws NotAuthorized
727
     * @throws NotFound
728
     * @throws NotImplemented
729
     * @throws InvalidRequest
730
     */
731
    private void describeObject(String pid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest
732
    {
733
        response.setContentType("text/xml");
734
735
        Identifier id = new Identifier();
736
        id.setValue(pid);
737 7043 leinfelder
738
        DescribeResponse dr = null;
739
        try {
740
            dr = CNodeService.getInstance(request).describe(session, id);
741
        } catch (BaseException e) {
742
        	response.setStatus(e.getCode());
743
        	response.addHeader("DataONE-Exception-Name", e.getClass().getName());
744
            response.addHeader("DataONE-Exception-DetailCode", e.getDetail_code());
745
            response.addHeader("DataONE-Exception-Description", e.getDescription());
746
            response.addHeader("DataONE-Exception-PID", id.getValue());
747
            return;
748
		}
749
750
        response.setStatus(200);
751 6803 leinfelder
        //response.addHeader("pid", pid);
752
        response.addHeader("DataONE-Checksum", dr.getDataONE_Checksum().getAlgorithm() + "," + dr.getDataONE_Checksum().getValue());
753
        response.addHeader("Content-Length", dr.getContent_Length() + "");
754
        response.addHeader("Last-Modified", DateTimeMarshaller.serializeDateToUTC(dr.getLast_Modified()));
755
        response.addHeader("DataONE-ObjectFormat", dr.getDataONE_ObjectFormatIdentifier().getValue());
756
        response.addHeader("DataONE-SerialVersion", dr.getSerialVersion().toString());
757
758
    }
759 7077 leinfelder
760
    /**
761
     * Handle delete
762
     * @param pid ID of data object to be deleted
763
     * @throws IOException
764
     * @throws InvalidRequest
765
     * @throws NotImplemented
766
     * @throws NotFound
767
     * @throws NotAuthorized
768
     * @throws ServiceFailure
769
     * @throws InvalidToken
770
     * @throws JiBXException
771
     */
772
    private void deleteObject(String pid) throws IOException, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, InvalidRequest, JiBXException
773
    {
774 6803 leinfelder
775 7077 leinfelder
        OutputStream out = response.getOutputStream();
776
        response.setStatus(200);
777
        response.setContentType("text/xml");
778
779
        Identifier id = new Identifier();
780
        id.setValue(pid);
781
782 7090 cjones
        logMetacat.debug("Calling delete for identifier " + pid);
783 7077 leinfelder
        CNodeService.getInstance(request).delete(session, id);
784
        TypeMarshaller.marshalTypeToOutputStream(id, out);
785
786
    }
787
788 6803 leinfelder
    /**
789 6253 leinfelder
     * Return the requested object format
790
     *
791 6756 cjones
     * @param fmtidStr
792
     *            the requested format identifier as a string
793
     * @throws NotImplemented
794
     * @throws InsufficientResources
795
     * @throws NotFound
796
     * @throws ServiceFailure
797
     * @throws InvalidRequest
798
     * @throws IOException
799
     * @throws JiBXException
800 6253 leinfelder
     */
801 6756 cjones
    private void getFormat(String fmtidStr) throws InvalidRequest,
802
            ServiceFailure, NotFound, InsufficientResources, NotImplemented,
803
            IOException, JiBXException {
804
        logMetacat.debug("Entering listFormats()");
805
806
        ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
807
        fmtid.setValue(fmtidStr);
808
809
        // get the specified object format
810
        ObjectFormat objectFormat = CNodeService.getInstance(request)
811
                .getFormat(fmtid);
812
813
        OutputStream out = response.getOutputStream();
814
        response.setStatus(200);
815
        response.setContentType("text/xml");
816
817
        TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
818
819 6253 leinfelder
    }
820 6756 cjones
821 6253 leinfelder
    /**
822
     * Reserve the given Identifier
823 6756 cjones
     *
824 6253 leinfelder
     * @throws InvalidToken
825
     * @throws ServiceFailure
826
     * @throws NotAuthorized
827
     * @throws IdentifierNotUnique
828
     * @throws NotImplemented
829
     * @throws InvalidRequest
830
     */
831 7095 cjones
    private void reserve()
832
        throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique,
833
        NotImplemented, InvalidRequest {
834 6756 cjones
        Identifier pid = null;
835
        String scope = null;
836
        String format = null;
837 7095 cjones
838
        // Parse the params out of the multipart form data
839
        logMetacat.debug("Parsing reserve parameters from the mime multipart entity");
840
        try {
841
            collectMultipartParams();
842
843
        } catch (FileUploadException e1) {
844
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
845
            e1.getMessage();
846
            logMetacat.debug(msg);
847
            throw new ServiceFailure("4210", msg);
848
849
        } catch (IOException e1) {
850
            String msg = "IOException: Couldn't parse the mime multipart information: " +
851
            e1.getMessage();
852
            logMetacat.debug(msg);
853
            throw new ServiceFailure("4210", msg);
854
855
        } catch (Exception e1) {
856
            String msg = "Exception: Couldn't parse the mime multipart information: " +
857
            e1.getMessage();
858
            logMetacat.debug(msg);
859
            throw new ServiceFailure("4210", msg);
860
861
        }
862
863 6756 cjones
        // gather the params
864
        try {
865 7095 cjones
            String id = multipartparams.get("pid").get(0);
866 6756 cjones
            pid = new Identifier();
867
            pid.setValue(id);
868 7095 cjones
869
        } catch (NullPointerException e) {
870
            String msg = "The 'pid' must be provided as a parameter and was not.";
871
            logMetacat.error(msg);
872
            throw new InvalidRequest("4200", msg);
873
874 6756 cjones
        }
875 7095 cjones
876
        // call the implementation
877 6756 cjones
        try {
878 7095 cjones
            Identifier resultPid = CNodeService.getInstance(request).reserveIdentifier(session, pid);
879
            OutputStream out = response.getOutputStream();
880
            response.setStatus(200);
881
            response.setContentType("text/xml");
882
            // send back the reserved pid
883
            TypeMarshaller.marshalTypeToOutputStream(resultPid, out);
884
885
        } catch (IOException e) {
886
            String msg = "Couldn't write the identifier to the response output stream: " +
887
                e.getMessage();
888
            logMetacat.debug(msg);
889
            throw new ServiceFailure("4210", msg);
890
891
        } catch (JiBXException e) {
892
            String msg = "Couldn't marshall the identifier to the response output stream: " +
893
            e.getMessage();
894
            logMetacat.debug(msg);
895
            throw new ServiceFailure("4210", msg);
896
897 6756 cjones
        }
898 6253 leinfelder
    }
899 6756 cjones
900 6270 leinfelder
    /**
901
     *
902
     * @param id
903
     * @throws InvalidRequest
904
     * @throws InvalidToken
905
     * @throws ServiceFailure
906
     * @throws NotAuthorized
907
     * @throws NotFound
908
     * @throws NotImplemented
909
     * @throws IOException
910 6756 cjones
     * @throws JiBXException
911 6270 leinfelder
     */
912 6756 cjones
    private void resolve(String id) throws InvalidRequest, InvalidToken,
913
            ServiceFailure, NotAuthorized, NotFound, NotImplemented,
914
            IOException, JiBXException {
915
        Identifier pid = new Identifier();
916
        pid.setValue(id);
917
        ObjectLocationList locationList = CNodeService.getInstance(request)
918
                .resolve(session, pid);
919
        OutputStream out = response.getOutputStream();
920
        response.setStatus(200);
921
        response.setContentType("text/xml");
922
        TypeMarshaller.marshalTypeToOutputStream(locationList, out);
923
924 6253 leinfelder
    }
925
926 6270 leinfelder
    /**
927
     * Set the owner of a resource
928 6756 cjones
     *
929 6270 leinfelder
     * @param id
930
     * @throws InvalidToken
931
     * @throws ServiceFailure
932
     * @throws NotFound
933
     * @throws NotAuthorized
934
     * @throws NotImplemented
935
     * @throws InvalidRequest
936 6756 cjones
     * @throws IllegalAccessException
937
     * @throws InstantiationException
938 6869 cjones
     * @throws VersionMismatch
939 6270 leinfelder
     */
940 7093 cjones
    private void owner(String id)
941 7094 cjones
        throws InvalidToken, ServiceFailure, NotFound, NotAuthorized,
942
        NotImplemented, InvalidRequest, InstantiationException,
943 7093 cjones
        IllegalAccessException, VersionMismatch {
944 6756 cjones
945 6592 cjones
        Identifier pid = new Identifier();
946 6756 cjones
        pid.setValue(id);
947 6592 cjones
948
        long serialVersion = 0L;
949
        String serialVersionStr = null;
950 7093 cjones
        String userIdStr = null;
951
        Subject userId = null;
952
953
        // Parse the params out of the multipart form data
954
        // Read the incoming data from its Mime Multipart encoding
955
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
956
        try {
957
            collectMultipartParams();
958
959
        } catch (FileUploadException e1) {
960
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
961
            e1.getMessage();
962
            logMetacat.debug(msg);
963
            throw new ServiceFailure("4490", msg);
964 6756 cjones
965 7093 cjones
        } catch (IOException e1) {
966
            String msg = "IOException: Couldn't parse the mime multipart information: " +
967
            e1.getMessage();
968
            logMetacat.debug(msg);
969
            throw new ServiceFailure("4490", msg);
970
971
        } catch (Exception e1) {
972
            String msg = "Exception: Couldn't parse the mime multipart information: " +
973
            e1.getMessage();
974
            logMetacat.debug(msg);
975
            throw new ServiceFailure("4490", msg);
976
977
        }
978
979 6592 cjones
        // get the serialVersion
980
        try {
981 7093 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
982 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
983 7093 cjones
984
        } catch (NumberFormatException nfe) {
985
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
986
            logMetacat.error(msg);
987
            throw new InvalidRequest("4442", msg);
988
989
        } catch (NullPointerException e) {
990
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
991
            logMetacat.error(msg);
992
            throw new InvalidRequest("4442", msg);
993
994
        }
995 6756 cjones
996 7093 cjones
        // get the subject userId that will become the rights holder
997
        try {
998
            userIdStr = multipartparams.get("userId").get(0);
999
            userId = new Subject();
1000
            userId.setValue(userIdStr);
1001
1002 6592 cjones
        } catch (NullPointerException e) {
1003
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1004
            logMetacat.error(msg);
1005
            throw new InvalidRequest("4442", msg);
1006 7093 cjones
1007
        }
1008 6756 cjones
1009 7093 cjones
        // set the rights holder
1010
        Identifier retPid = CNodeService.getInstance(request).setRightsHolder(session, pid, userId, serialVersion);
1011
1012
        try {
1013
            OutputStream out = response.getOutputStream();
1014
            response.setStatus(200);
1015
            response.setContentType("text/xml");
1016
            TypeMarshaller.marshalTypeToOutputStream(retPid, out);
1017
1018
        } catch (IOException e) {
1019
            String msg = "Couldn't write the identifier to the response output stream: " +
1020
                e.getMessage();
1021
            logMetacat.debug(msg);
1022
            throw new ServiceFailure("4490", msg);
1023 7094 cjones
1024
        } catch (JiBXException e) {
1025
            String msg = "Couldn't marshall the identifier to the response output stream: " +
1026
            e.getMessage();
1027
            logMetacat.debug(msg);
1028
            throw new ServiceFailure("4490", msg);
1029
1030 6756 cjones
        }
1031 6253 leinfelder
    }
1032 6756 cjones
1033 6270 leinfelder
    /**
1034
     * Processes the authorization check for given id
1035 6756 cjones
     *
1036 6270 leinfelder
     * @param id
1037
     * @return
1038
     * @throws ServiceFailure
1039
     * @throws InvalidToken
1040
     * @throws NotFound
1041
     * @throws NotAuthorized
1042
     * @throws NotImplemented
1043
     * @throws InvalidRequest
1044
     */
1045 6756 cjones
    private boolean isAuthorized(String id) throws ServiceFailure,
1046
            InvalidToken, NotFound, NotAuthorized, NotImplemented,
1047
            InvalidRequest {
1048
        Identifier pid = new Identifier();
1049
        pid.setValue(id);
1050
        String permission = params.get("action")[0];
1051
        boolean result = CNodeService.getInstance(request).isAuthorized(
1052
                session, pid, Permission.convert(permission));
1053
        response.setStatus(200);
1054
        response.setContentType("text/xml");
1055
        return result;
1056 6253 leinfelder
    }
1057 6756 cjones
1058 6253 leinfelder
    /**
1059
     * Register System Metadata without data or metadata object
1060 6756 cjones
     *
1061
     * @param pid
1062
     *            identifier for System Metadata entry
1063
     * @throws JiBXException
1064
     * @throws FileUploadException
1065
     * @throws IOException
1066
     * @throws InvalidRequest
1067
     * @throws ServiceFailure
1068
     * @throws InvalidSystemMetadata
1069
     * @throws NotAuthorized
1070
     * @throws NotImplemented
1071
     * @throws IllegalAccessException
1072
     * @throws InstantiationException
1073 6253 leinfelder
     */
1074 6974 leinfelder
    protected void registerSystemMetadata()
1075 6756 cjones
            throws ServiceFailure, InvalidRequest, IOException,
1076
            FileUploadException, JiBXException, NotImplemented, NotAuthorized,
1077
            InvalidSystemMetadata, InstantiationException,
1078
            IllegalAccessException {
1079 6974 leinfelder
1080
    	// Read the incoming data from its Mime Multipart encoding
1081
        Map<String, File> files = collectMultipartFiles();
1082
1083
    	// get the encoded pid string from the body and make the object
1084 6975 leinfelder
        String pidString = multipartparams.get("pid").get(0);
1085
        Identifier pid = new Identifier();
1086
        pid.setValue(pidString);
1087 6974 leinfelder
1088
        logMetacat.debug("registerSystemMetadata: " + pid);
1089 6253 leinfelder
1090 6756 cjones
        // get the system metadata from the request
1091 6974 leinfelder
        File smFile = files.get("sysmeta");
1092
        FileInputStream sysmeta = new FileInputStream(smFile);
1093
        SystemMetadata systemMetadata = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
1094 6253 leinfelder
1095 6974 leinfelder
        logMetacat.debug("registering system metadata with pid " + pid.getValue());
1096
        Identifier retGuid = CNodeService.getInstance(request).registerSystemMetadata(session, pid, systemMetadata);
1097 6756 cjones
1098 6880 leinfelder
        OutputStream out = response.getOutputStream();
1099 6756 cjones
        response.setStatus(200);
1100
        response.setContentType("text/xml");
1101 6880 leinfelder
1102
        TypeMarshaller.marshalTypeToOutputStream(retGuid, out);
1103 6756 cjones
1104
    }
1105
1106 6268 leinfelder
    /**
1107
     * set the access perms on a document
1108 6756 cjones
     *
1109
     * @throws JiBXException
1110
     * @throws InvalidRequest
1111
     * @throws NotImplemented
1112
     * @throws NotAuthorized
1113
     * @throws NotFound
1114
     * @throws ServiceFailure
1115
     * @throws InvalidToken
1116
     * @throws IllegalAccessException
1117
     * @throws InstantiationException
1118
     * @throws IOException
1119
     * @throws SAXException
1120
     * @throws ParserConfigurationException
1121 6869 cjones
     * @throws VersionMismatch
1122 6268 leinfelder
     */
1123 6756 cjones
    protected void setAccess(String pid) throws JiBXException, InvalidToken,
1124
            ServiceFailure, NotFound, NotAuthorized, NotImplemented,
1125
            InvalidRequest, IOException, InstantiationException,
1126 6869 cjones
            IllegalAccessException, ParserConfigurationException, SAXException, VersionMismatch {
1127 6270 leinfelder
1128 6592 cjones
        long serialVersion = 0L;
1129
        String serialVersionStr = null;
1130 7090 cjones
        AccessPolicy accessPolicy = collectAccessPolicy();
1131 6756 cjones
1132 6592 cjones
        // get the serialVersion
1133
        try {
1134 7090 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1135 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
1136 6756 cjones
1137 7090 cjones
        } catch (NumberFormatException nfe) {
1138
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1139
            logMetacat.error(msg);
1140
            throw new InvalidRequest("4402", msg);
1141
1142 6592 cjones
        } catch (NullPointerException e) {
1143
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1144
            logMetacat.error(msg);
1145
            throw new InvalidRequest("4402", msg);
1146 6756 cjones
1147 6592 cjones
        }
1148 6756 cjones
1149 6270 leinfelder
        Identifier id = new Identifier();
1150 6514 leinfelder
        id.setValue(pid);
1151 6756 cjones
1152
        CNodeService.getInstance(request).setAccessPolicy(session, id,
1153
                accessPolicy, serialVersion);
1154 6270 leinfelder
1155 6268 leinfelder
    }
1156 6756 cjones
1157 6268 leinfelder
    /**
1158 6756 cjones
     * List the objects
1159
     *
1160
     * @throws NotImplemented
1161
     * @throws InvalidRequest
1162
     * @throws NotAuthorized
1163
     * @throws ServiceFailure
1164
     * @throws InvalidToken
1165
     * @throws NotFound
1166
     * @throws IOException
1167 6622 leinfelder
     * @throws JiBXException
1168 6268 leinfelder
     * @throws Exception
1169
     */
1170 6756 cjones
    private void listObjects() throws InvalidToken, ServiceFailure,
1171
            NotAuthorized, InvalidRequest, NotImplemented, NotFound,
1172
            IOException, JiBXException {
1173 6622 leinfelder
1174 6756 cjones
        Date startTime = null;
1175
        Date endTime = null;
1176 7100 leinfelder
        ObjectFormatIdentifier formatId = null;
1177 6756 cjones
        boolean replicaStatus = false;
1178
        int start = 0;
1179
        int count = -1;
1180
        Enumeration<String> paramlist = request.getParameterNames();
1181
        while (paramlist.hasMoreElements()) {
1182
            // parse the params and make the call
1183
            String name = paramlist.nextElement();
1184 7048 leinfelder
            String[] values = request.getParameterValues(name);
1185
            String value = null;
1186
            if (values != null && values.length > 0) {
1187
            	value = values[0];
1188
            	value = EncodingUtilities.decodeString(value);
1189
            }
1190 6622 leinfelder
1191 7046 cjones
            if (name.equals("fromDate") && value != null) {
1192 6756 cjones
                try {
1193 7048 leinfelder
                    startTime = DateTimeMarshaller.deserializeDateToUTC(value);
1194 6756 cjones
                } catch (Exception e) {
1195
                    // if we can't parse it, just don't use the startTime param
1196 7048 leinfelder
                    logMetacat.warn("Could not parse fromDate: " + value);
1197 6756 cjones
                    startTime = null;
1198
                }
1199 7046 cjones
            } else if (name.equals("toDate") && value != null) {
1200 6756 cjones
                try {
1201 7048 leinfelder
                    endTime = DateTimeMarshaller.deserializeDateToUTC(value);
1202 6756 cjones
                } catch (Exception e) {
1203
                    // if we can't parse it, just don't use the endTime param
1204 7048 leinfelder
                    logMetacat.warn("Could not parse toDate: " + value);
1205 6756 cjones
                    endTime = null;
1206
                }
1207 7100 leinfelder
            } else if (name.equals("formatId") && value != null) {
1208
            	formatId = new ObjectFormatIdentifier();
1209
            	formatId.setValue(value);
1210 6756 cjones
            } else if (name.equals("replicaStatus") && value != null) {
1211 7048 leinfelder
                replicaStatus = Boolean.parseBoolean(value);
1212 6756 cjones
            } else if (name.equals("start") && value != null) {
1213 7048 leinfelder
                start = Integer.valueOf(value);
1214 6756 cjones
            } else if (name.equals("count") && value != null) {
1215 7048 leinfelder
                count = Integer.valueOf(value);
1216 6756 cjones
            }
1217
        }
1218
        // make the call
1219 7046 cjones
        logMetacat.debug("session: " + session + " fromDate: " + startTime
1220 7100 leinfelder
                + " toDate: " + endTime + " formatId: " + formatId
1221 6756 cjones
                + " replicaStatus: " + replicaStatus + " start: " + start
1222 7048 leinfelder
                + " count: " + count);
1223 6622 leinfelder
1224 6756 cjones
        // get the list
1225
        ObjectList ol = CNodeService.getInstance(request).listObjects(session,
1226 7100 leinfelder
                startTime, endTime, formatId, replicaStatus, start, count);
1227 6756 cjones
1228
        // send it
1229
        OutputStream out = response.getOutputStream();
1230
        response.setStatus(200);
1231
        response.setContentType("text/xml");
1232
1233
        // style the object with a processing directive
1234
        String stylesheet = null;
1235
        try {
1236
            stylesheet = PropertyService.getProperty("dataone.types.xsl");
1237
        } catch (PropertyNotFoundException e) {
1238
            logMetacat.warn("Could not locate DataONE types XSLT: "
1239
                    + e.getMessage());
1240
        }
1241
1242
        // Serialize and write it to the output stream
1243
        TypeMarshaller.marshalTypeToOutputStream(ol, out, stylesheet);
1244
    }
1245
1246 6592 cjones
    /**
1247
     * Pass the request to get node replication authorization to CNodeService
1248
     *
1249 6756 cjones
     * @param pid
1250
     *            the identifier of the object to get authorization to replicate
1251 6592 cjones
     *
1252
     * @throws NotImplemented
1253
     * @throws NotAuthorized
1254
     * @throws InvalidToken
1255
     * @throws ServiceFailure
1256
     * @throws NotFound
1257
     * @throws InvalidRequest
1258
     */
1259 6756 cjones
    public boolean isNodeAuthorized(String pid) throws NotImplemented,
1260
            NotAuthorized, InvalidToken, ServiceFailure, NotFound,
1261
            InvalidRequest {
1262
1263 6592 cjones
        boolean result = false;
1264
        Subject targetNodeSubject = new Subject();
1265
        String nodeSubject = null;
1266
        String replPermission = null;
1267 6756 cjones
1268 6592 cjones
        // get the pid
1269
        Identifier identifier = new Identifier();
1270
        identifier.setValue(pid);
1271 6756 cjones
1272 6592 cjones
        // get the target node subject
1273
        try {
1274
            nodeSubject = params.get("targetNodeSubject")[0];
1275
            targetNodeSubject.setValue(nodeSubject);
1276 6756 cjones
1277 6592 cjones
        } catch (NullPointerException e) {
1278
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
1279
            logMetacat.error(msg);
1280
            throw new InvalidRequest("4873", msg);
1281 6756 cjones
1282 6592 cjones
        }
1283 6756 cjones
1284 6777 leinfelder
        result = CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier);
1285 6268 leinfelder
1286 6592 cjones
        response.setStatus(200);
1287
        response.setContentType("text/xml");
1288
        return result;
1289 6756 cjones
1290 6592 cjones
    }
1291 6756 cjones
1292 6592 cjones
    /**
1293
     * Pass the request to set the replication policy to CNodeService
1294
     *
1295 6756 cjones
     * @param pid
1296
     *            the identifier of the object to set the replication policy on
1297 6592 cjones
     *
1298
     * @throws NotImplemented
1299
     * @throws NotFound
1300
     * @throws NotAuthorized
1301
     * @throws ServiceFailure
1302
     * @throws InvalidRequest
1303
     * @throws InvalidToken
1304
     * @throws IOException
1305
     * @throws InstantiationException
1306
     * @throws IllegalAccessException
1307
     * @throws JiBXException
1308 6869 cjones
     * @throws VersionMismatch
1309 6592 cjones
     */
1310 6756 cjones
    public boolean setReplicationPolicy(String pid) throws NotImplemented,
1311
            NotFound, NotAuthorized, ServiceFailure, InvalidRequest,
1312
            InvalidToken, IOException, InstantiationException,
1313 6869 cjones
            IllegalAccessException, JiBXException, VersionMismatch {
1314 6756 cjones
1315 6592 cjones
        boolean result = false;
1316
        ReplicationPolicy policy = null;
1317
        long serialVersion = 0L;
1318
        String serialVersionStr = null;
1319 6756 cjones
1320 6592 cjones
        Identifier identifier = new Identifier();
1321
        identifier.setValue(pid);
1322 6756 cjones
1323 6634 cjones
        policy = collectReplicationPolicy();
1324
1325 6592 cjones
        // get the serialVersion
1326
        try {
1327 6603 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1328 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
1329 6756 cjones
1330 6592 cjones
        } catch (NullPointerException e) {
1331
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1332
            logMetacat.error(msg);
1333
            throw new InvalidRequest("4883", msg);
1334 6756 cjones
1335 6592 cjones
        }
1336 6756 cjones
        result = CNodeService.getInstance(request).setReplicationPolicy(
1337
                session, identifier, policy, serialVersion);
1338 6592 cjones
        response.setStatus(200);
1339
        response.setContentType("text/xml");
1340
        return result;
1341 6756 cjones
1342 6592 cjones
    }
1343 6890 leinfelder
1344 7096 cjones
    /**
1345
     * Update the system metadata for a given pid, setting it to be obsoleted
1346
     * by the obsoletedByPid
1347
     *
1348
     * @param pid
1349
     * @return
1350
     * @throws NotImplemented
1351
     * @throws NotFound
1352
     * @throws NotAuthorized
1353
     * @throws ServiceFailure
1354
     * @throws InvalidRequest
1355
     * @throws InvalidToken
1356
     * @throws InstantiationException
1357
     * @throws IllegalAccessException
1358
     * @throws VersionMismatch
1359
     */
1360
    public boolean setObsoletedBy(String pid)
1361
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1362
        InvalidRequest, InvalidToken, InstantiationException,
1363
        IllegalAccessException, VersionMismatch {
1364
1365
        boolean result = false;
1366
        long serialVersion = 0L;
1367
        String serialVersionStr = null;
1368
1369
        Identifier identifier = new Identifier();
1370
        identifier.setValue(pid);
1371
        String obsoletedByPidString = null;
1372
        Identifier obsoletedByPid = null;
1373
1374
        // Parse the params out of the multipart form data
1375
        // Read the incoming data from its Mime Multipart encoding
1376
        logMetacat.debug("Parsing rights holder parameters from the mime multipart entity");
1377
        try {
1378
            collectMultipartParams();
1379
1380
        } catch (FileUploadException e1) {
1381
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1382
            e1.getMessage();
1383
            logMetacat.debug(msg);
1384
            throw new ServiceFailure("4941", msg);
1385
1386
        } catch (IOException e1) {
1387
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1388
            e1.getMessage();
1389
            logMetacat.debug(msg);
1390
            throw new ServiceFailure("4941", msg);
1391
1392
        } catch (Exception e1) {
1393
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1394
            e1.getMessage();
1395
            logMetacat.debug(msg);
1396
            throw new ServiceFailure("4941", msg);
1397
1398
        }
1399
1400
        // get the obsoletedByPid
1401
        try {
1402
            obsoletedByPidString = multipartparams.get("obsoletedByPid").get(0);
1403
            obsoletedByPid = new Identifier();
1404
            obsoletedByPid.setValue(obsoletedByPidString);
1405
        } catch (NullPointerException e) {
1406
            String msg = "The 'obsoletedByPid' must be provided as a parameter and was not.";
1407
            logMetacat.error(msg);
1408
            throw new InvalidRequest("4883", msg);
1409
        }
1410
1411
        // get the serialVersion
1412
        try {
1413
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1414
            serialVersion = new Long(serialVersionStr).longValue();
1415
1416
        } catch (NumberFormatException nfe) {
1417
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1418
            logMetacat.error(msg);
1419
            throw new InvalidRequest("4942", msg);
1420
1421
        } catch (NullPointerException e) {
1422
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1423
            logMetacat.error(msg);
1424
            throw new InvalidRequest("4942", msg);
1425
1426
        }
1427
        result = CNodeService.getInstance(request).setObsoletedBy(session,
1428
            identifier, obsoletedByPid, serialVersion);
1429
        response.setStatus(200);
1430
        response.setContentType("text/xml");
1431
        return result;
1432
1433
    }
1434 6891 leinfelder
1435 7097 cjones
    /**
1436
     * Delete the replica entry with the given nodeId for the given pid
1437
     *
1438
     * @param pid
1439
     * @return
1440
     * @throws NotImplemented
1441
     * @throws NotFound
1442
     * @throws NotAuthorized
1443
     * @throws ServiceFailure
1444
     * @throws InvalidRequest
1445
     * @throws InvalidToken
1446
     * @throws InstantiationException
1447
     * @throws IllegalAccessException
1448
     * @throws VersionMismatch
1449
     */
1450
    public boolean deleteReplica(String pid)
1451
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
1452
        InvalidRequest, InvalidToken, InstantiationException,
1453
        IllegalAccessException, VersionMismatch {
1454 6891 leinfelder
1455 7097 cjones
        boolean result = false;
1456
        long serialVersion = 0L;
1457
        String serialVersionStr = null;
1458 6891 leinfelder
1459 7097 cjones
        Identifier identifier = new Identifier();
1460
        identifier.setValue(pid);
1461 6891 leinfelder
1462 7097 cjones
        NodeReference nodeId = null;
1463
1464
        // Parse the params out of the multipart form data
1465
        // Read the incoming data from its Mime Multipart encoding
1466
        logMetacat.debug("Parsing delete replica parameters from the mime multipart entity");
1467
        try {
1468
            collectMultipartParams();
1469
1470
        } catch (FileUploadException e1) {
1471
            String msg = "FileUploadException: Couldn't parse the mime multipart information: " +
1472
            e1.getMessage();
1473
            logMetacat.debug(msg);
1474
            throw new ServiceFailure("4951", msg);
1475 6891 leinfelder
1476 7097 cjones
        } catch (IOException e1) {
1477
            String msg = "IOException: Couldn't parse the mime multipart information: " +
1478
            e1.getMessage();
1479
            logMetacat.debug(msg);
1480
            throw new ServiceFailure("4951", msg);
1481
1482
        } catch (Exception e1) {
1483
            String msg = "Exception: Couldn't parse the mime multipart information: " +
1484
            e1.getMessage();
1485
            logMetacat.debug(msg);
1486
            throw new ServiceFailure("4951", msg);
1487 6891 leinfelder
1488 7097 cjones
        }
1489
1490
        // get the nodeId param
1491
        try {
1492
            String nodeIdString = multipartparams.get("nodeId").get(0);
1493
            nodeId = new NodeReference();
1494
            nodeId.setValue(nodeIdString);
1495
1496
        } catch (NullPointerException e) {
1497
            String msg = "The 'nodeId' must be provided as a parameter and was not.";
1498
            logMetacat.error(msg);
1499
            throw new InvalidRequest("4952", msg);
1500
        }
1501 6891 leinfelder
1502 7097 cjones
        // get the serialVersion
1503
        try {
1504
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1505
            serialVersion = new Long(serialVersionStr).longValue();
1506
1507
        } catch (NumberFormatException nfe) {
1508
            String msg = "The 'serialVersion' must be provided as a positive integer and was not.";
1509
            logMetacat.error(msg);
1510
            throw new InvalidRequest("4952", msg);
1511
1512
        } catch (NullPointerException e) {
1513
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1514
            logMetacat.error(msg);
1515
            throw new InvalidRequest("4952", msg);
1516
1517
        }
1518
        result = CNodeService.getInstance(request).deleteReplicationMetadata(
1519
                session, identifier, nodeId, serialVersion);
1520
        response.setStatus(200);
1521
        response.setContentType("text/xml");
1522
        return result;
1523 6891 leinfelder
1524 7097 cjones
    }
1525 6756 cjones
1526 6592 cjones
    /**
1527
     * Pass the request to set the replication status to CNodeService
1528
     *
1529 6756 cjones
     * @param pid
1530
     *            the identifier of the object to set the replication status on
1531 6592 cjones
     *
1532
     * @throws ServiceFailure
1533
     * @throws NotImplemented
1534
     * @throws InvalidToken
1535
     * @throws NotAuthorized
1536
     * @throws InvalidRequest
1537
     * @throws NotFound
1538 6794 cjones
     * @throws JiBXException
1539
     * @throws IllegalAccessException
1540
     * @throws InstantiationException
1541
     * @throws IOException
1542 6592 cjones
     */
1543 6756 cjones
    public boolean setReplicationStatus(String pid) throws ServiceFailure,
1544
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1545
            NotFound {
1546 6794 cjones
1547 6592 cjones
        boolean result = false;
1548
        Identifier identifier = new Identifier();
1549
        identifier.setValue(pid);
1550 6794 cjones
        BaseException failure = null;
1551 6592 cjones
        ReplicationStatus status = null;
1552
        String replicationStatus = null;
1553
        NodeReference targetNodeRef = null;
1554
        String targetNode = null;
1555 6756 cjones
1556 6634 cjones
        // Parse the params out of the multipart form data
1557
        // Read the incoming data from its Mime Multipart encoding
1558 6794 cjones
        logMetacat.debug("Parsing ReplicaStatus from the mime multipart entity");
1559 6634 cjones
1560
        try {
1561 6794 cjones
            failure = collectReplicationStatus();
1562
1563
        } catch (IOException e2) {
1564
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1565
                e2.getMessage());
1566
1567
        } catch (InstantiationException e2) {
1568
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1569
                e2.getMessage());
1570
1571
        } catch (IllegalAccessException e2) {
1572
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1573
                    e2.getMessage());
1574
1575
        } catch (JiBXException e2) {
1576
            throw new ServiceFailure("4700", "Couldn't resolve the multipart request: " +
1577
                    e2.getMessage());
1578
1579 6634 cjones
        }
1580 6794 cjones
1581 6592 cjones
        // get the replication status param
1582
        try {
1583 6643 cjones
            replicationStatus = multipartparams.get("status").get(0);
1584 6592 cjones
            status = ReplicationStatus.convert(replicationStatus);
1585 6677 cjones
1586 6642 cjones
        } catch (NullPointerException npe) {
1587
1588 6756 cjones
            logMetacat.debug("The 'status' parameter was not found in the "
1589
                    + "multipartparams map.  Trying the params map.");
1590
1591 6642 cjones
            try {
1592 6643 cjones
                replicationStatus = params.get("status")[0];
1593 6756 cjones
                status = ReplicationStatus.convert(replicationStatus
1594
                        .toLowerCase());
1595
1596 6642 cjones
            } catch (Exception e) {
1597 6643 cjones
                String msg = "The 'status' must be provided as a parameter and was not.";
1598 6642 cjones
                logMetacat.error(msg);
1599
                throw new InvalidRequest("4730", msg);
1600 6756 cjones
1601 6642 cjones
            }
1602 6756 cjones
1603 6592 cjones
        }
1604 6756 cjones
1605 6592 cjones
        // get the target node reference param
1606 6642 cjones
        try {
1607
            targetNode = multipartparams.get("nodeRef").get(0);
1608
            targetNodeRef = new NodeReference();
1609
            targetNodeRef.setValue(targetNode);
1610 6756 cjones
1611 6642 cjones
        } catch (NullPointerException e) {
1612 6756 cjones
            logMetacat.debug("The 'nodeRef' parameter was not found in the "
1613
                    + "multipartparams map.  Trying the params map.");
1614
1615 6642 cjones
            try {
1616
                targetNode = params.get("nodeRef")[0];
1617
                targetNodeRef = new NodeReference();
1618
                targetNodeRef.setValue(targetNode);
1619 6756 cjones
1620 6642 cjones
            } catch (Exception e1) {
1621
                String msg = "The 'nodeRef' must be provided as a parameter and was not.";
1622
                logMetacat.error(msg);
1623
                throw new InvalidRequest("4730", msg);
1624 6756 cjones
1625 6642 cjones
            }
1626 6756 cjones
1627 6642 cjones
        }
1628 6756 cjones
1629
        result = CNodeService.getInstance(request).setReplicationStatus(
1630 6794 cjones
                session, identifier, targetNodeRef, status, failure);
1631 6592 cjones
        response.setStatus(200);
1632
        response.setContentType("text/xml");
1633
        return result;
1634 6756 cjones
1635 6592 cjones
    }
1636 6756 cjones
1637 6592 cjones
    /**
1638
     * Pass the request to update the replication metadata to CNodeService
1639
     *
1640 6756 cjones
     * @param pid
1641
     *            the identifier of the object to update the replication
1642
     *            metadata on
1643 6592 cjones
     *
1644
     * @throws ServiceFailure
1645
     * @throws NotImplemented
1646
     * @throws InvalidToken
1647
     * @throws NotAuthorized
1648
     * @throws InvalidRequest
1649
     * @throws NotFound
1650 6869 cjones
     * @throws VersionMismatch
1651 6592 cjones
     */
1652 6756 cjones
    public boolean updateReplicationMetadata(String pid) throws ServiceFailure,
1653
            NotImplemented, InvalidToken, NotAuthorized, InvalidRequest,
1654 6869 cjones
            NotFound, VersionMismatch {
1655 6592 cjones
1656
        boolean result = false;
1657
        long serialVersion = 0L;
1658
        String serialVersionStr = null;
1659
        Replica replica = null;
1660
        Identifier identifier = new Identifier();
1661
        identifier.setValue(pid);
1662
1663 6634 cjones
        replica = collectReplicaMetadata();
1664 6756 cjones
1665 6592 cjones
        // get the serialVersion
1666
        try {
1667 6603 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1668 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
1669 6756 cjones
1670 6592 cjones
        } catch (NullPointerException e) {
1671
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1672
            logMetacat.error(msg);
1673
            throw new InvalidRequest("4853", msg);
1674 6756 cjones
1675 6592 cjones
        }
1676
1677 6756 cjones
        result = CNodeService.getInstance(request).updateReplicationMetadata(
1678
                session, identifier, replica, serialVersion);
1679 6592 cjones
        response.setStatus(200);
1680
        response.setContentType("text/xml");
1681
        return result;
1682
1683
    }
1684
1685 6253 leinfelder
}