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.ByteArrayInputStream;
26
import java.io.File;
27
import java.io.FileInputStream;
28
import java.io.IOException;
29
import java.io.InputStream;
30
import java.io.OutputStream;
31
import java.util.Date;
32
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 6366 leinfelder
import org.dataone.service.types.v1.AccessPolicy;
55
import org.dataone.service.types.v1.Checksum;
56
import org.dataone.service.types.v1.Event;
57
import org.dataone.service.types.v1.Identifier;
58
import org.dataone.service.types.v1.Log;
59 6592 cjones
import org.dataone.service.types.v1.NodeReference;
60 6366 leinfelder
import org.dataone.service.types.v1.ObjectFormat;
61
import org.dataone.service.types.v1.ObjectFormatIdentifier;
62
import org.dataone.service.types.v1.ObjectFormatList;
63
import org.dataone.service.types.v1.ObjectLocationList;
64
import org.dataone.service.types.v1.Permission;
65 6592 cjones
import org.dataone.service.types.v1.Replica;
66
import org.dataone.service.types.v1.ReplicationPolicy;
67
import org.dataone.service.types.v1.ReplicationStatus;
68
import org.dataone.service.types.v1.Session;
69 6366 leinfelder
import org.dataone.service.types.v1.Subject;
70
import org.dataone.service.types.v1.SystemMetadata;
71 6469 leinfelder
import org.dataone.service.util.DateTimeMarshaller;
72 6367 leinfelder
import org.dataone.service.util.TypeMarshaller;
73 6253 leinfelder
import org.jibx.runtime.JiBXException;
74 6514 leinfelder
import org.xml.sax.SAXException;
75 6253 leinfelder
76
import edu.ucsb.nceas.metacat.dataone.CNodeService;
77
78
/**
79
 * CN REST service implementation handler
80
 *
81
 * ******************
82
 	CNCore -- DONE
83
		create() - POST /d1/cn/object/PID
84
		listFormats() - GET /d1/cn/formats
85
		getFormat() - GET /d1/cn/formats/FMTID
86
		getLogRecords - GET /d1/cn/log
87
		reserveIdentifier() - POST /d1/cn/reserve
88
		listNodes() - Not implemented
89
		registerSystemMetadata() - POST /d1/meta/PID
90
91
	CNRead -- DONE
92
		get() - GET /d1/cn/object/PID
93
		getSystemMetadata() - GET /d1/cn/meta/PID
94
		resolve() - GET /d1/cn/resolve/PID
95
		assertRelation() - GET /d1/cn/assertRelation/PID
96
		getChecksum() - GET /d1/cn/checksum
97
		search() - Not implemented in Metacat
98
99
	CNAuthorization
100
		setOwner() - PUT /d1/cn/owner/PID
101
		isAuthorized() - GET /d1/cn/isAuthorized/PID
102
		setAccessPolicy() - POST /d1/cn/accessRules
103
104
	CNIdentity - not implemented at all on Metacat
105
106
	CNReplication
107 6592 cjones
		setReplicationStatus() - PUT /replicationNotifications/PID
108
		updateReplicationMetadata() - PUT /replicationMetadata/PID
109
		setReplicationPolicy() - PUT /replicationPolicies/PID
110
		isNodeAuthorized() - GET /replicationAuthorizations/PID
111 6253 leinfelder
112
	CNRegister -- not implemented at all in Metacat
113
 * ******************
114
 * @author leinfelder
115
 *
116
 */
117 6267 leinfelder
public class CNResourceHandler extends D1ResourceHandler {
118 6253 leinfelder
119
	/** CN-specific operations **/
120
    protected static final String RESOURCE_RESERVE = "reserve";
121 6271 leinfelder
    protected static final String RESOURCE_FORMATS = "formats";
122 6253 leinfelder
    protected static final String RESOURCE_RESOLVE = "resolve";
123
    protected static final String RESOURCE_ASSERT_RELATION = "assertRelation";
124
    protected static final String RESOURCE_OWNER = "owner";
125 6592 cjones
    protected static final String RESOURCE_REPLICATION_POLICY = "replicaPolicies";
126
    protected static final String RESOURCE_REPLICATION_META = "replicaMetadata";
127
    protected static final String RESOURCE_REPLICATION_AUTHORIZED = "replicaAuthorizations";
128
    protected static final String RESOURCE_REPLICATION_NOTIFY = "replicaNotifications";
129 6253 leinfelder
130
    public CNResourceHandler(ServletContext servletContext,
131
			HttpServletRequest request, HttpServletResponse response) {
132
		super(servletContext, request, response);
133
        logMetacat = Logger.getLogger(CNResourceHandler.class);
134
	}
135
136
	/**
137 6271 leinfelder
     * This function is called from REST API servlet and handles each request to the servlet
138 6253 leinfelder
     *
139
     * @param httpVerb (GET, POST, PUT or DELETE)
140
     */
141 6271 leinfelder
    @Override
142 6253 leinfelder
    public void handle(byte httpVerb) {
143 6271 leinfelder
    	// prepare the handler
144
    	super.handle(httpVerb);
145
146 6253 leinfelder
        try {
147 6282 leinfelder
148
        	// get the resource
149
            String resource = request.getPathInfo();
150
            resource = resource.substring(resource.indexOf("/") + 1);
151 6253 leinfelder
152 6396 leinfelder
            // for the rest of the resouce
153 6282 leinfelder
            String extra = null;
154
155 6253 leinfelder
            logMetacat.debug("handling verb " + httpVerb + " request with resource '" + resource + "'");
156
            boolean status = false;
157 6271 leinfelder
158 6253 leinfelder
            if (resource != null) {
159
160 6282 leinfelder
                if (resource.startsWith(RESOURCE_ACCESS_RULES) && httpVerb == PUT) {
161 6253 leinfelder
                    logMetacat.debug("Setting access policy");
162 6514 leinfelder
                    // after the command
163
                    extra = parseTrailing(resource, RESOURCE_ACCESS_RULES);
164
                    setAccess(extra);
165 6253 leinfelder
                    status = true;
166
                    logMetacat.debug("done setting access");
167
168 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_META)) {
169 6253 leinfelder
                    logMetacat.debug("Using resource: " + RESOURCE_META);
170 6282 leinfelder
171 6396 leinfelder
                    // after the command
172
                    extra = parseTrailing(resource, RESOURCE_META);
173
174 6253 leinfelder
                    // get
175
                    if (httpVerb == GET) {
176 6282 leinfelder
                        getSystemMetadataObject(extra);
177 6253 leinfelder
                        status = true;
178
                    }
179
                    // post to register system metadata
180
                    if (httpVerb == POST) {
181 6282 leinfelder
                    	registerSystemMetadata(extra);
182 6253 leinfelder
                    	status = true;
183
                    }
184
185 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_RESERVE)) {
186 6253 leinfelder
                    // reserve the ID (in params)
187
                    if (httpVerb == POST) {
188
                    	reserve();
189
                    	status = true;
190
                    }
191 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_ASSERT_RELATION)) {
192
193 6396 leinfelder
                	// after the command
194
                    extra = parseTrailing(resource, RESOURCE_ASSERT_RELATION);
195
196 6253 leinfelder
                    // reserve the ID (in params)
197
                    if (httpVerb == GET) {
198 6282 leinfelder
                    	assertRelation(extra);
199 6253 leinfelder
                    	status = true;
200
                    }
201 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_RESOLVE)) {
202
203 6396 leinfelder
                	// after the command
204
                    extra = parseTrailing(resource, RESOURCE_RESOLVE);
205
206 6253 leinfelder
                    // resolve the object location
207
                    if (httpVerb == GET) {
208 6282 leinfelder
                    	resolve(extra);
209 6253 leinfelder
                    	status = true;
210
                    }
211 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_OWNER)) {
212
213 6396 leinfelder
                	// after the command
214
                    extra = parseTrailing(resource, RESOURCE_OWNER);
215
216 6253 leinfelder
                    // set the owner
217
                    if (httpVerb == PUT) {
218 6282 leinfelder
                    	owner(extra);
219 6253 leinfelder
                    	status = true;
220
                    }
221 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_IS_AUTHORIZED)) {
222
223 6396 leinfelder
                	// after the command
224
                    extra = parseTrailing(resource, RESOURCE_IS_AUTHORIZED);
225
226 6253 leinfelder
                    // authorized?
227
                    if (httpVerb == GET) {
228 6282 leinfelder
                    	isAuthorized(extra);
229 6253 leinfelder
                    	status = true;
230
                    }
231 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_OBJECTS)) {
232 6253 leinfelder
                    logMetacat.debug("Using resource 'object'");
233
                    logMetacat.debug("D1 Rest: Starting resource processing...");
234
235 6396 leinfelder
                    // after the command
236
                    extra = parseTrailing(resource, RESOURCE_OBJECTS);
237
238 6282 leinfelder
                    logMetacat.debug("objectId: " + extra);
239 6253 leinfelder
                    logMetacat.debug("verb:" + httpVerb);
240
241
                    if (httpVerb == GET) {
242 6282 leinfelder
                    	if (extra != null) {
243
                    		getObject(extra);
244
                    	} else {
245
                    		query();
246
                    	}
247 6253 leinfelder
                        status = true;
248
                    } else if (httpVerb == POST) {
249 6282 leinfelder
                        putObject(extra, FUNCTION_NAME_INSERT);
250 6253 leinfelder
                        status = true;
251
                    }
252
253 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_FORMATS)) {
254 6253 leinfelder
                  logMetacat.debug("Using resource: " + RESOURCE_FORMATS);
255
256 6396 leinfelder
                  // after the command
257
                  extra = parseTrailing(resource, RESOURCE_FORMATS);
258 6253 leinfelder
259
                  // handle each verb
260
                  if (httpVerb == GET) {
261 6282 leinfelder
                  	if (extra == null) {
262 6253 leinfelder
                  		// list the formats collection
263
                  		listFormats();
264
                  	} else {
265
                  		// get the specified format
266 6282 leinfelder
                  		getFormat(extra);
267 6253 leinfelder
                  	}
268
                  	status = true;
269
                  }
270
271 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_LOG)) {
272 6253 leinfelder
                    logMetacat.debug("Using resource: " + RESOURCE_LOG);
273
                    //handle log events
274
                    if (httpVerb == GET) {
275
                        getLog();
276
                        status = true;
277
                    }
278
279 6282 leinfelder
                } else if (resource.startsWith(RESOURCE_CHECKSUM)) {
280 6253 leinfelder
                    logMetacat.debug("Using resource: " + RESOURCE_CHECKSUM);
281 6396 leinfelder
282
                    // after the command
283
                    extra = parseTrailing(resource, RESOURCE_CHECKSUM);
284
285 6253 leinfelder
                    //handle checksum requests
286
                    if (httpVerb == GET) {
287
288 6282 leinfelder
                        checksum(extra);
289 6253 leinfelder
                        status = true;
290 6592 cjones
291 6253 leinfelder
                    }
292 6592 cjones
293
                } else if ( resource.startsWith(RESOURCE_REPLICATION_POLICY) &&
294
                        httpVerb == PUT) {
295
296
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_POLICY);
297
                    // get the trailing pid
298
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_POLICY);
299
                    setReplicationPolicy(extra);
300
                    status = true;
301
302
                } else if ( resource.startsWith(RESOURCE_REPLICATION_META) &&
303
                        httpVerb == PUT) {
304
305
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_META);
306
                    // get the trailing pid
307
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_META);
308
                    updateReplicationMetadata(extra);
309
                    status = true;
310
311
                } else if ( resource.startsWith(RESOURCE_REPLICATION_NOTIFY) &&
312
                        httpVerb == PUT ) {
313
314
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_NOTIFY);
315
                    // get the trailing pid
316
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_NOTIFY);
317
                    setReplicationStatus(extra);
318
                    status = true;
319
320
                } else if ( resource.startsWith(RESOURCE_REPLICATION_AUTHORIZED)
321
                        && httpVerb == GET) {
322
323
                    logMetacat.debug("Using resource: " + RESOURCE_REPLICATION_AUTHORIZED);
324
                    // get the trailing pid
325
                    extra = parseTrailing(resource, RESOURCE_REPLICATION_AUTHORIZED);
326
                    isNodeAuthorized(extra);
327
                    status = true;
328
329 6253 leinfelder
                }
330
331
                if (!status) {
332 6271 leinfelder
                	throw new ServiceFailure("0000", "Unknown error, status = " + status);
333 6253 leinfelder
                }
334
            } else {
335 6270 leinfelder
            	throw new InvalidRequest("0000", "No resource matched for " + resource);
336 6253 leinfelder
            }
337
        } catch (BaseException be) {
338 6270 leinfelder
        	// report Exceptions as clearly and generically as possible
339 6253 leinfelder
        	OutputStream out = null;
340
			try {
341
				out = response.getOutputStream();
342 6270 leinfelder
			} catch (IOException ioe) {
343
				logMetacat.error("Could not get output stream from response", ioe);
344 6253 leinfelder
			}
345
            serializeException(be, out);
346
        } catch (Exception e) {
347 6270 leinfelder
            // report Exceptions as clearly and generically as possible
348 6253 leinfelder
            logMetacat.error(e.getClass() + ": " + e.getMessage(), e);
349 6270 leinfelder
        	OutputStream out = null;
350
			try {
351
				out = response.getOutputStream();
352
			} catch (IOException ioe) {
353
				logMetacat.error("Could not get output stream from response", ioe);
354
			}
355
			ServiceFailure se = new ServiceFailure("0000", e.getMessage());
356
            serializeException(se, out);
357 6253 leinfelder
        }
358
    }
359
360 6396 leinfelder
361 6270 leinfelder
    /**
362
     * Get the checksum for the given guid
363
     *
364
     * @param guid
365
     * @throws NotImplemented
366
     * @throws InvalidRequest
367
     * @throws NotFound
368
     * @throws NotAuthorized
369
     * @throws ServiceFailure
370
     * @throws InvalidToken
371
     * @throws IOException
372
     * @throws JiBXException
373
     */
374
    private void checksum(String guid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, JiBXException, IOException {
375
    	Identifier guidid = new Identifier();
376
        guidid.setValue(guid);
377
        logMetacat.debug("getting checksum for object " + guid);
378 6542 leinfelder
        Checksum c = CNodeService.getInstance(request).getChecksum(session, guidid);
379 6270 leinfelder
        logMetacat.debug("got checksum " + c.getValue());
380
        response.setStatus(200);
381
        logMetacat.debug("serializing response");
382 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(c, response.getOutputStream());
383 6270 leinfelder
        logMetacat.debug("done serializing response.");
384
385
    }
386
387 6253 leinfelder
	/**
388 6362 leinfelder
     * get the logs based on passed params.  Available
389 6253 leinfelder
     * params are token, fromDate, toDate, event.  See
390
     * http://mule1.dataone.org/ArchitectureDocs/mn_api_crud.html#MN_crud.getLogRecords
391
     * for more info
392 6270 leinfelder
	 * @throws NotImplemented
393
	 * @throws InvalidRequest
394
	 * @throws NotAuthorized
395
	 * @throws ServiceFailure
396
	 * @throws InvalidToken
397
	 * @throws IOException
398
	 * @throws JiBXException
399 6253 leinfelder
     */
400 6270 leinfelder
    private void getLog() throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented, IOException, JiBXException
401 6253 leinfelder
    {
402 6270 leinfelder
403
        Date fromDate = null;
404
        Date toDate = null;
405
        Event event = null;
406
        Integer start = null;
407
        Integer count = null;
408
409
        try {
410
        	String fromDateS = params.get("fromDate")[0];
411 6272 leinfelder
            logMetacat.debug("param fromDateS: " + fromDateS);
412 6469 leinfelder
            fromDate = DateTimeMarshaller.deserializeDateToUTC(fromDateS);
413 6270 leinfelder
        } catch (Exception e) {
414
        	logMetacat.warn("Could not parse fromDate: " + e.getMessage());
415 6253 leinfelder
        }
416 6270 leinfelder
        try {
417
        	String toDateS = params.get("toDate")[0];
418 6272 leinfelder
            logMetacat.debug("param toDateS: " + toDateS);
419 6469 leinfelder
            toDate = DateTimeMarshaller.deserializeDateToUTC(toDateS);
420 6270 leinfelder
        } catch (Exception e) {
421
        	logMetacat.warn("Could not parse toDate: " + e.getMessage());
422
		}
423
        try {
424
        	String eventS = params.get("event")[0];
425
            event = Event.convert(eventS);
426
        } catch (Exception e) {
427
        	logMetacat.warn("Could not parse event: " + e.getMessage());
428
		}
429 6272 leinfelder
        logMetacat.debug("fromDate: " + fromDate + " toDate: " + toDate);
430 6270 leinfelder
431
        try {
432
        	start =  Integer.parseInt(params.get("start")[0]);
433
        } catch (Exception e) {
434
			logMetacat.warn("Could not parse start: " + e.getMessage());
435
		}
436
        try {
437
        	count =  Integer.parseInt(params.get("count")[0]);
438
        } catch (Exception e) {
439
			logMetacat.warn("Could not parse count: " + e.getMessage());
440
		}
441
442 6272 leinfelder
        logMetacat.debug("calling getLogRecords");
443 6542 leinfelder
        Log log = CNodeService.getInstance(request).getLogRecords(session, fromDate, toDate, event, start, count);
444 6270 leinfelder
445
        OutputStream out = response.getOutputStream();
446
        response.setStatus(200);
447
        response.setContentType("text/xml");
448
449 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(log, out);
450 6270 leinfelder
451 6253 leinfelder
    }
452
453
    /**
454
     * Implements REST version of DataONE CRUD API --> get
455
     * @param guid ID of data object to be read
456 6270 leinfelder
     * @throws NotImplemented
457
     * @throws InvalidRequest
458
     * @throws NotFound
459
     * @throws NotAuthorized
460
     * @throws ServiceFailure
461
     * @throws InvalidToken
462
     * @throws IOException
463 6253 leinfelder
     */
464 6270 leinfelder
    protected void getObject(String guid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException {
465
466 6280 leinfelder
        Identifier id = new Identifier();
467
        id.setValue(guid);
468
469 6542 leinfelder
        SystemMetadata sm = CNodeService.getInstance(request).getSystemMetadata(session, id);
470 6270 leinfelder
471 6280 leinfelder
        //set the content type
472 6561 leinfelder
        if(sm.getFormatId().getValue().trim().equals(
473
        		ObjectFormatCache.getInstance().getFormat("text/csv").getFormatId().getValue()))
474 6280 leinfelder
        {
475
            response.setContentType("text/csv");
476
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".csv");
477 6253 leinfelder
        }
478 6561 leinfelder
        else if(sm.getFormatId().getValue().trim().equals(
479
        		ObjectFormatCache.getInstance().getFormat("text/plain").getFormatId().getValue()))
480 6280 leinfelder
        {
481
            response.setContentType("text/plain");
482
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".txt");
483
        }
484 6561 leinfelder
        else if(sm.getFormatId().getValue().trim().equals(
485
        		ObjectFormatCache.getInstance().getFormat("application/octet-stream").getFormatId().getValue()))
486 6280 leinfelder
        {
487
            response.setContentType("application/octet-stream");
488
        }
489
        else
490
        {
491
            response.setContentType("text/xml");
492
            response.setHeader("Content-Disposition", "inline; filename=" + id.getValue() + ".xml");
493
        }
494
495 6542 leinfelder
        InputStream data = CNodeService.getInstance(request).get(session, id);
496 6280 leinfelder
497
        OutputStream out = response.getOutputStream();
498
        response.setStatus(200);
499
        IOUtils.copyLarge(data, out);
500 6270 leinfelder
501 6253 leinfelder
    }
502
503
504
    /**
505
     * Implements REST version of DataONE CRUD API --> getSystemMetadata
506
     * @param guid ID of data object to be read
507 6270 leinfelder
     * @throws NotImplemented
508
     * @throws InvalidRequest
509
     * @throws NotFound
510
     * @throws NotAuthorized
511
     * @throws ServiceFailure
512
     * @throws InvalidToken
513
     * @throws IOException
514
     * @throws JiBXException
515 6253 leinfelder
     */
516 6270 leinfelder
    protected void getSystemMetadataObject(String guid) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented, IOException, JiBXException {
517
518
        Identifier id = new Identifier();
519
        id.setValue(guid);
520 6542 leinfelder
        SystemMetadata sysmeta = CNodeService.getInstance(request).getSystemMetadata(session, id);
521 6270 leinfelder
522
        response.setContentType("text/xml");
523
        response.setStatus(200);
524
        OutputStream out = response.getOutputStream();
525
526
        // Serialize and write it to the output stream
527 6367 leinfelder
        TypeMarshaller.marshalTypeToOutputStream(sysmeta, out);
528 6270 leinfelder
   }
529 6253 leinfelder
530
    /**
531
     * Earthgrid API > Put Service >Put Function : calls MetacatHandler > handleInsertOrUpdateAction
532
     *
533
     * @param guid - ID of data object to be inserted or updated.  If action is update, the pid
534
     *               is the existing pid.  If insert, the pid is the new one
535 6269 leinfelder
     * @throws InvalidRequest
536
     * @throws ServiceFailure
537
     * @throws IdentifierNotUnique
538
     * @throws JiBXException
539
     * @throws NotImplemented
540
     * @throws InvalidSystemMetadata
541
     * @throws InsufficientResources
542
     * @throws UnsupportedType
543
     * @throws NotAuthorized
544
     * @throws InvalidToken
545
     * @throws IOException
546 6367 leinfelder
     * @throws IllegalAccessException
547
     * @throws InstantiationException
548 6253 leinfelder
     */
549 6367 leinfelder
    protected void putObject(String pid, String action) throws ServiceFailure, InvalidRequest, IdentifierNotUnique, JiBXException, InvalidToken, NotAuthorized, UnsupportedType, InsufficientResources, InvalidSystemMetadata, NotImplemented, IOException, InstantiationException, IllegalAccessException {
550 6253 leinfelder
        logMetacat.debug("Entering putObject: " + pid + "/" + action);
551 6269 leinfelder
552
        // Read the incoming data from its Mime Multipart encoding
553
    	Map<String, File> files = collectMultipartFiles();
554
        InputStream object = null;
555
        InputStream sysmeta = null;
556 6253 leinfelder
557 6269 leinfelder
        File smFile = files.get("sysmeta");
558
        sysmeta = new FileInputStream(smFile);
559
        File objFile = files.get("object");
560
        object = new FileInputStream(objFile);
561
562 6270 leinfelder
        if (action.equals(FUNCTION_NAME_INSERT)) { //handle inserts
563 6253 leinfelder
564 6269 leinfelder
            logMetacat.debug("Commence creation...");
565 6367 leinfelder
            SystemMetadata smd = TypeMarshaller.unmarshalTypeFromStream(SystemMetadata.class, sysmeta);
566 6253 leinfelder
567 6269 leinfelder
            Identifier id = new Identifier();
568
            id.setValue(pid);
569
            logMetacat.debug("creating object with pid " + id.getValue());
570 6542 leinfelder
            Identifier rId = CNodeService.getInstance(request).create(session, id, object, smd);
571 6253 leinfelder
572 6269 leinfelder
            OutputStream out = response.getOutputStream();
573
            response.setStatus(200);
574
            response.setContentType("text/xml");
575 6253 leinfelder
576 6367 leinfelder
            TypeMarshaller.marshalTypeToOutputStream(rId, out);
577 6269 leinfelder
578
        } else {
579
            throw new InvalidRequest("1000", "Operation must be create.");
580 6253 leinfelder
        }
581
    }
582
583
    /**
584
     * List the object formats registered with the system
585 6270 leinfelder
     * @throws NotImplemented
586
     * @throws InsufficientResources
587
     * @throws NotFound
588
     * @throws ServiceFailure
589
     * @throws InvalidRequest
590
     * @throws IOException
591
     * @throws JiBXException
592 6253 leinfelder
     */
593 6270 leinfelder
	private void listFormats() throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources, NotImplemented, IOException, JiBXException {
594 6253 leinfelder
      logMetacat.debug("Entering listFormats()");
595 6270 leinfelder
596 6542 leinfelder
      ObjectFormatList objectFormatList = CNodeService.getInstance(request).listFormats();
597 6253 leinfelder
      // get the response output stream
598 6270 leinfelder
      OutputStream out = response.getOutputStream();
599
      response.setStatus(200);
600
      response.setContentType("text/xml");
601 6253 leinfelder
602 6367 leinfelder
      TypeMarshaller.marshalTypeToOutputStream(objectFormatList, out);
603 6270 leinfelder
604 6253 leinfelder
    }
605
606
		/**
607
     * Return the requested object format
608
     *
609
     * @param fmtidStr the requested format identifier as a string
610 6270 leinfelder
		 * @throws NotImplemented
611
		 * @throws InsufficientResources
612
		 * @throws NotFound
613
		 * @throws ServiceFailure
614
		 * @throws InvalidRequest
615
		 * @throws IOException
616
		 * @throws JiBXException
617 6253 leinfelder
     */
618 6270 leinfelder
    private void getFormat(String fmtidStr) throws InvalidRequest, ServiceFailure, NotFound, InsufficientResources, NotImplemented, IOException, JiBXException {
619 6253 leinfelder
      logMetacat.debug("Entering listFormats()");
620
621
      ObjectFormatIdentifier fmtid = new ObjectFormatIdentifier();
622
      fmtid.setValue(fmtidStr);
623
624 6270 leinfelder
	  // get the specified object format
625 6542 leinfelder
      ObjectFormat objectFormat = CNodeService.getInstance(request).getFormat(fmtid);
626 6253 leinfelder
627 6270 leinfelder
      OutputStream out = response.getOutputStream();
628
      response.setStatus(200);
629
      response.setContentType("text/xml");
630 6253 leinfelder
631 6367 leinfelder
      TypeMarshaller.marshalTypeToOutputStream(objectFormat, out);
632 6253 leinfelder
633
    }
634
635
    /**
636
     * Reserve the given Identifier
637
     * @throws InvalidToken
638
     * @throws ServiceFailure
639
     * @throws NotAuthorized
640
     * @throws IdentifierNotUnique
641
     * @throws NotImplemented
642
     * @throws InvalidRequest
643
     * @throws IOException
644 6270 leinfelder
     * @throws JiBXException
645 6253 leinfelder
     */
646 6270 leinfelder
    private void reserve() throws InvalidToken, ServiceFailure, NotAuthorized, IdentifierNotUnique, NotImplemented, InvalidRequest, IOException, JiBXException {
647 6279 leinfelder
		Identifier pid = null;
648
		String scope = null;
649
    	String format = null;
650
    	// gather the params
651
		try {
652
	    	String id = params.get("pid")[0];
653
			pid = new Identifier();
654
			pid.setValue(id);
655
		} catch (Exception e) {
656
			logMetacat.warn("pid not specified");
657
		}
658
		try {
659
			scope = params.get("scope")[0];
660
		} catch (Exception e) {
661
			logMetacat.warn("pid not specified");
662
		}
663
		try {
664
			format = params.get("format")[0];
665
		} catch (Exception e) {
666
			logMetacat.warn("pid not specified");
667
		}
668
		// call the implementation
669 6542 leinfelder
		boolean result = CNodeService.getInstance(request).reserveIdentifier(session, pid);
670 6253 leinfelder
		OutputStream out = response.getOutputStream();
671
		response.setStatus(200);
672
		response.setContentType("text/xml");
673 6378 leinfelder
		// nothing to send back
674 6253 leinfelder
    }
675
676 6270 leinfelder
    /**
677
     *
678
     * @param id
679
     * @throws InvalidRequest
680
     * @throws InvalidToken
681
     * @throws ServiceFailure
682
     * @throws NotAuthorized
683
     * @throws NotFound
684
     * @throws NotImplemented
685
     * @throws IOException
686
     * @throws JiBXException
687
     */
688
    private void resolve(String id) throws InvalidRequest, InvalidToken, ServiceFailure, NotAuthorized, NotFound, NotImplemented, IOException, JiBXException {
689 6253 leinfelder
		Identifier pid = new Identifier();
690
		pid.setValue(id);
691 6542 leinfelder
		ObjectLocationList locationList = CNodeService.getInstance(request).resolve(session, pid);
692 6253 leinfelder
	    OutputStream out = response.getOutputStream();
693
		response.setStatus(200);
694
		response.setContentType("text/xml");
695 6367 leinfelder
		TypeMarshaller.marshalTypeToOutputStream(locationList, out);
696 6270 leinfelder
697 6253 leinfelder
    }
698
699 6270 leinfelder
    /**
700
     * Assert that a relationship exists between two resources
701
     * @param id
702
     * @return
703
     * @throws InvalidToken
704
     * @throws ServiceFailure
705
     * @throws NotAuthorized
706
     * @throws NotFound
707
     * @throws InvalidRequest
708
     * @throws NotImplemented
709
     */
710 6268 leinfelder
    private boolean assertRelation(String id) throws InvalidToken, ServiceFailure, NotAuthorized, NotFound, InvalidRequest, NotImplemented {
711 6253 leinfelder
		Identifier pidOfSubject = new Identifier();
712
		pidOfSubject.setValue(id);
713 6270 leinfelder
		String relationship = null;
714
		try {
715
			relationship = params.get("relationship")[0];
716
		} catch (Exception e) {
717
			logMetacat.warn("relationship not specified");
718
		}
719 6253 leinfelder
		Identifier pidOfObject = new Identifier();
720 6270 leinfelder
		try {
721
			String objPid = params.get("pidOfObject")[0];
722
			pidOfObject.setValue(objPid);
723
		} catch (Exception e) {
724
			logMetacat.warn("pidOfObject not specified");
725
		}
726 6542 leinfelder
		boolean result = CNodeService.getInstance(request).assertRelation(session, pidOfSubject, relationship, pidOfObject);
727 6253 leinfelder
		response.setStatus(200);
728
		response.setContentType("text/xml");
729
		return result;
730
    }
731
732 6270 leinfelder
    /**
733
     * Set the owner of a resource
734
     * @param id
735
     * @throws JiBXException
736
     * @throws InvalidToken
737
     * @throws ServiceFailure
738
     * @throws NotFound
739
     * @throws NotAuthorized
740
     * @throws NotImplemented
741
     * @throws InvalidRequest
742
     * @throws IOException
743 6367 leinfelder
     * @throws IllegalAccessException
744
     * @throws InstantiationException
745 6270 leinfelder
     */
746 6592 cjones
    private void owner(String id)
747
        throws JiBXException, InvalidToken, ServiceFailure,
748
        NotFound, NotAuthorized, NotImplemented, InvalidRequest, IOException,
749
        InstantiationException, IllegalAccessException {
750
751
        Identifier pid = new Identifier();
752
		    pid.setValue(id);
753
754
        long serialVersion = 0L;
755
        String serialVersionStr = null;
756
757
        // get the serialVersion
758
        try {
759
            serialVersionStr = params.get("serialVersion")[0];
760
            serialVersion = new Long(serialVersionStr).longValue();
761
762
        } catch (NullPointerException e) {
763
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
764
            logMetacat.error(msg);
765
            throw new InvalidRequest("4442", msg);
766
767
        }
768
769
		    // get the subject
770
		    String subjectStr = params.get("subject")[0];
771
		    Subject subject = TypeMarshaller.unmarshalTypeFromStream(Subject.class, new ByteArrayInputStream(subjectStr.getBytes("UTF-8")));
772
773
		    Identifier retPid = CNodeService.getInstance(request).setOwner(session, pid, subject, serialVersion);
774
		    OutputStream out = response.getOutputStream();
775
		    response.setStatus(200);
776
		    response.setContentType("text/xml");
777
		    TypeMarshaller.marshalTypeToOutputStream(retPid, out);
778 6253 leinfelder
    }
779
780 6270 leinfelder
    /**
781
     * Processes the authorization check for given id
782
     * @param id
783
     * @return
784
     * @throws ServiceFailure
785
     * @throws InvalidToken
786
     * @throws NotFound
787
     * @throws NotAuthorized
788
     * @throws NotImplemented
789
     * @throws InvalidRequest
790
     */
791 6253 leinfelder
    private boolean isAuthorized(String id) throws ServiceFailure, InvalidToken, NotFound, NotAuthorized, NotImplemented, InvalidRequest {
792
		Identifier pid = new Identifier();
793
		pid.setValue(id);
794 6510 leinfelder
		String permission = params.get("action")[0];
795 6542 leinfelder
		boolean result = CNodeService.getInstance(request).isAuthorized(session, pid, Permission.convert(permission));
796 6253 leinfelder
		response.setStatus(200);
797
		response.setContentType("text/xml");
798
		return result;
799
    }
800
801
    /**
802
     * Register System Metadata without data or metadata object
803
     * @param pid identifier for System Metadata entry
804 6269 leinfelder
     * @throws JiBXException
805
     * @throws FileUploadException
806
     * @throws IOException
807
     * @throws InvalidRequest
808
     * @throws ServiceFailure
809
     * @throws InvalidSystemMetadata
810
     * @throws NotAuthorized
811
     * @throws NotImplemented
812 6367 leinfelder
     * @throws IllegalAccessException
813
     * @throws InstantiationException
814 6253 leinfelder
     */
815 6397 leinfelder
    protected Identifier registerSystemMetadata(String pid) throws ServiceFailure, InvalidRequest, IOException, FileUploadException, JiBXException, NotImplemented, NotAuthorized, InvalidSystemMetadata, InstantiationException, IllegalAccessException {
816 6253 leinfelder
		logMetacat.debug("Entering registerSystemMetadata: " + pid);
817
818 6269 leinfelder
		// get the system metadata from the request
819
		SystemMetadata systemMetadata = collectSystemMetadata();
820 6253 leinfelder
821 6269 leinfelder
		Identifier guid = new Identifier();
822
		guid.setValue(pid);
823
		logMetacat.debug("registering system metadata with pid " + guid.getValue());
824 6542 leinfelder
		Identifier retGuid = CNodeService.getInstance(request).registerSystemMetadata(session, guid, systemMetadata);
825 6269 leinfelder
826
		response.setStatus(200);
827
		response.setContentType("text/xml");
828 6397 leinfelder
		return retGuid;
829 6269 leinfelder
830 6253 leinfelder
	}
831 6268 leinfelder
832
    /**
833
     * set the access perms on a document
834 6270 leinfelder
     * @throws JiBXException
835
     * @throws InvalidRequest
836
     * @throws NotImplemented
837
     * @throws NotAuthorized
838
     * @throws NotFound
839
     * @throws ServiceFailure
840
     * @throws InvalidToken
841 6367 leinfelder
     * @throws IllegalAccessException
842
     * @throws InstantiationException
843
     * @throws IOException
844 6514 leinfelder
     * @throws SAXException
845
     * @throws ParserConfigurationException
846 6268 leinfelder
     */
847 6592 cjones
    protected void setAccess(String pid)
848
        throws JiBXException, InvalidToken, ServiceFailure, NotFound,
849
        NotAuthorized, NotImplemented, InvalidRequest, IOException,
850
        InstantiationException, IllegalAccessException, ParserConfigurationException,
851
        SAXException {
852 6270 leinfelder
853 6592 cjones
        long serialVersion = 0L;
854
        String serialVersionStr = null;
855
856
        // get the serialVersion
857
        try {
858
            serialVersionStr = params.get("serialVersion")[0];
859
            serialVersion = new Long(serialVersionStr).longValue();
860
861
        } catch (NullPointerException e) {
862
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
863
            logMetacat.error(msg);
864
            throw new InvalidRequest("4402", msg);
865
866
        }
867
868 6270 leinfelder
        Identifier id = new Identifier();
869 6514 leinfelder
        id.setValue(pid);
870
871
        AccessPolicy accessPolicy = collectAccessPolicy();
872 6592 cjones
        CNodeService.getInstance(request).setAccessPolicy(session, id, accessPolicy, serialVersion);
873 6270 leinfelder
874 6268 leinfelder
    }
875
876
    /**
877 6282 leinfelder
     *	Pass to the CN search service
878
     *
879
     * @throws NotImplemented
880
     * @throws InvalidRequest
881
     * @throws NotAuthorized
882
     * @throws ServiceFailure
883
     * @throws InvalidToken
884 6268 leinfelder
     * @throws Exception
885
     */
886 6592 cjones
    private void query()
887
        throws InvalidToken, ServiceFailure, NotAuthorized, InvalidRequest, NotImplemented {
888 6282 leinfelder
889 6592 cjones
    	  String query = null;
890
		    String queryType = null;
891
		    try {
892
		    	query = params.get("query")[0];
893
		    } catch (Exception e) {
894
		    	logMetacat.warn("query not specified");
895
		    }
896
		    try {
897
		    	String qt = params.get("queryType")[0];
898
		    	queryType = qt;
899
		    } catch (Exception e) {
900
		    	logMetacat.warn("queryType not specified");
901
		    }
902
903
        	// expecting to throw NotImplemented
904
		    CNodeService.getInstance(request).search(session, queryType, query);
905 6268 leinfelder
    }
906 6592 cjones
907
    /**
908
     * Pass the request to get node replication authorization to CNodeService
909
     *
910
     * @param pid  the identifier of the object to get authorization to replicate
911
     *
912
     * @throws NotImplemented
913
     * @throws NotAuthorized
914
     * @throws InvalidToken
915
     * @throws ServiceFailure
916
     * @throws NotFound
917
     * @throws InvalidRequest
918
     */
919
    public boolean isNodeAuthorized(String pid)
920
        throws NotImplemented, NotAuthorized, InvalidToken, ServiceFailure,
921
        NotFound, InvalidRequest {
922
923
        boolean result = false;
924
        Subject targetNodeSubject = new Subject();
925
        String nodeSubject = null;
926
        Permission permission = null;
927
        String replPermission = null;
928
929
        // get the pid
930
        Identifier identifier = new Identifier();
931
        identifier.setValue(pid);
932
933
        // get the target node subject
934
        try {
935
            nodeSubject = params.get("targetNodeSubject")[0];
936
            targetNodeSubject.setValue(nodeSubject);
937
938
        } catch (NullPointerException e) {
939
            String msg = "The 'targetNodeSubject' must be provided as a parameter and was not.";
940
            logMetacat.error(msg);
941
            throw new InvalidRequest("4873", msg);
942
943
        }
944
945
        // get the permission
946
        try {
947
            replPermission = params.get("replicatePermission")[0];
948
            permission = Permission.convert(replPermission);
949 6268 leinfelder
950 6592 cjones
        } catch (NullPointerException e) {
951
            String msg = "The 'replicatePermission' must be provided as a parameter and was not.";
952
            logMetacat.error(msg);
953
            throw new InvalidRequest("4873", msg);
954
955
        }
956
957
        result =
958
            CNodeService.getInstance(request).isNodeAuthorized(session, targetNodeSubject, identifier, permission);
959
960
        response.setStatus(200);
961
        response.setContentType("text/xml");
962
        return result;
963
964
    }
965
966
    /**
967
     * Pass the request to set the replication policy to CNodeService
968
     *
969
     * @param pid  the identifier of the object to set the replication policy on
970
     *
971
     * @throws NotImplemented
972
     * @throws NotFound
973
     * @throws NotAuthorized
974
     * @throws ServiceFailure
975
     * @throws InvalidRequest
976
     * @throws InvalidToken
977
     * @throws IOException
978
     * @throws InstantiationException
979
     * @throws IllegalAccessException
980
     * @throws JiBXException
981
     */
982
    public boolean setReplicationPolicy(String pid)
983
        throws NotImplemented, NotFound, NotAuthorized, ServiceFailure,
984
        InvalidRequest, InvalidToken, IOException, InstantiationException,
985
        IllegalAccessException, JiBXException {
986
987
        boolean result = false;
988
        ReplicationPolicy policy = null;
989
        long serialVersion = 0L;
990
        String serialVersionStr = null;
991
992
        Identifier identifier = new Identifier();
993
        identifier.setValue(pid);
994
995
        // get the serialVersion
996
        try {
997 6603 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
998 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
999
1000
        } catch (NullPointerException e) {
1001
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1002
            logMetacat.error(msg);
1003
            throw new InvalidRequest("4883", msg);
1004
1005
        }
1006
        policy = collectReplicationPolicy();
1007
        result =
1008
            CNodeService.getInstance(request).setReplicationPolicy(session, identifier, policy, serialVersion);
1009
        response.setStatus(200);
1010
        response.setContentType("text/xml");
1011
        return result;
1012
1013
    }
1014
1015
    /**
1016
     * Pass the request to set the replication status to CNodeService
1017
     *
1018
     * @param pid  the identifier of the object to set the replication status on
1019
     *
1020
     * @throws ServiceFailure
1021
     * @throws NotImplemented
1022
     * @throws InvalidToken
1023
     * @throws NotAuthorized
1024
     * @throws InvalidRequest
1025
     * @throws NotFound
1026
     */
1027
    public boolean setReplicationStatus(String pid)
1028
        throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
1029
        InvalidRequest, NotFound {
1030
1031
        boolean result = false;
1032
        Identifier identifier = new Identifier();
1033
        identifier.setValue(pid);
1034
        long serialVersion = 0L;
1035
        String serialVersionStr = null;
1036
        ReplicationStatus status = null;
1037
        String replicationStatus = null;
1038
        NodeReference targetNodeRef = null;
1039
        String targetNode = null;
1040
1041
        // get the serialVersion
1042
        try {
1043 6603 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1044 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
1045
1046
        } catch (NullPointerException e) {
1047
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1048
            logMetacat.error(msg);
1049
            throw new InvalidRequest("4730", msg);
1050
1051
        }
1052
1053
        // get the replication status param
1054
        try {
1055 6603 cjones
            replicationStatus = multipartparams.get("replicationStatus").get(0);
1056 6592 cjones
            status = ReplicationStatus.convert(replicationStatus);
1057
        } catch (Exception e) {
1058
            // TODO Auto-generated catch block
1059
            e.printStackTrace();
1060
        }
1061
1062
        // get the target node reference param
1063 6603 cjones
        targetNode = multipartparams.get("nodeRef").get(0);
1064 6592 cjones
        targetNodeRef = new NodeReference();
1065
        targetNodeRef.setValue(targetNode);
1066
1067
        result =
1068
            CNodeService.getInstance(request).setReplicationStatus(session, identifier, targetNodeRef, status, serialVersion);
1069
        response.setStatus(200);
1070
        response.setContentType("text/xml");
1071
        return result;
1072
1073
    }
1074
1075
    /**
1076
     * Pass the request to update the replication metadata to CNodeService
1077
     *
1078
     * @param pid  the identifier of the object to update the replication metadata on
1079
     *
1080
     * @throws ServiceFailure
1081
     * @throws NotImplemented
1082
     * @throws InvalidToken
1083
     * @throws NotAuthorized
1084
     * @throws InvalidRequest
1085
     * @throws NotFound
1086
     */
1087
    public boolean updateReplicationMetadata(String pid)
1088
        throws ServiceFailure, NotImplemented, InvalidToken, NotAuthorized,
1089
        InvalidRequest, NotFound {
1090
1091
        boolean result = false;
1092
        long serialVersion = 0L;
1093
        String serialVersionStr = null;
1094
        Replica replica = null;
1095
        Identifier identifier = new Identifier();
1096
        identifier.setValue(pid);
1097
1098
        // get the serialVersion
1099
        try {
1100 6603 cjones
            serialVersionStr = multipartparams.get("serialVersion").get(0);
1101 6592 cjones
            serialVersion = new Long(serialVersionStr).longValue();
1102
1103
        } catch (NullPointerException e) {
1104
            String msg = "The 'serialVersion' must be provided as a parameter and was not.";
1105
            logMetacat.error(msg);
1106
            throw new InvalidRequest("4853", msg);
1107
1108
        }
1109
1110
        replica = collectReplicaMetadata();
1111
        result =
1112
            CNodeService.getInstance(request).updateReplicationMetadata(session, identifier, replica, serialVersion);
1113
        response.setStatus(200);
1114
        response.setContentType("text/xml");
1115
        return result;
1116
1117
    }
1118
1119 6253 leinfelder
}