001: /*---------------- FILE HEADER ------------------------------------------
002: This file is part of adv ebrim project.
003: Copyright (C) 2007 by:
004:
005: Andreas Poth
006: lat/lon GmbH
007: Aennchenstr. 19
008: 53177 Bonn
009: Germany
010: E-Mail: poth@lat-lon.de
011:
012: ---------------------------------------------------------------------------*/
013:
014: package de.latlon.adv;
015:
016: import java.io.IOException;
017: import java.net.URI;
018: import java.net.URISyntaxException;
019: import java.security.InvalidParameterException;
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.List;
023: import java.util.Map;
024: import java.util.UUID;
025:
026: import org.deegree.datatypes.QualifiedName;
027: import org.deegree.framework.log.ILogger;
028: import org.deegree.framework.log.LoggerFactory;
029: import org.deegree.framework.util.TimeTools;
030: import org.deegree.framework.xml.XMLParsingException;
031: import org.deegree.framework.xml.XMLTools;
032: import org.deegree.io.datastore.schema.MappedFeatureType;
033: import org.deegree.model.feature.Feature;
034: import org.deegree.model.feature.FeatureCollection;
035: import org.deegree.model.feature.FeatureFactory;
036: import org.deegree.model.feature.FeatureProperty;
037: import org.deegree.model.filterencoding.ComplexFilter;
038: import org.deegree.model.filterencoding.Expression;
039: import org.deegree.model.filterencoding.Literal;
040: import org.deegree.model.filterencoding.OperationDefines;
041: import org.deegree.model.filterencoding.PropertyIsCOMPOperation;
042: import org.deegree.model.filterencoding.PropertyName;
043: import org.deegree.ogcbase.CommonNamespaces;
044: import org.deegree.ogcbase.PropertyPath;
045: import org.deegree.ogcbase.PropertyPathFactory;
046: import org.deegree.ogcwebservices.OGCWebServiceException;
047: import org.deegree.ogcwebservices.csw.manager.Insert;
048: import org.deegree.ogcwebservices.csw.manager.Manager;
049: import org.deegree.ogcwebservices.csw.manager.Operation;
050: import org.deegree.ogcwebservices.csw.manager.Transaction;
051: import org.deegree.ogcwebservices.csw.manager.TransactionResult;
052: import org.deegree.ogcwebservices.wfs.WFService;
053: import org.deegree.ogcwebservices.wfs.XMLFactory;
054: import org.deegree.ogcwebservices.wfs.operation.FeatureResult;
055: import org.deegree.ogcwebservices.wfs.operation.GetFeatureDocument;
056: import org.deegree.ogcwebservices.wfs.operation.GetFeatureWithLock;
057: import org.deegree.ogcwebservices.wfs.operation.Query;
058: import org.deegree.ogcwebservices.wfs.operation.GetFeature.RESULT_TYPE;
059: import org.deegree.ogcwebservices.wfs.operation.LockFeature.ALL_SOME_TYPE;
060: import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionDocument;
061: import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionOperation;
062: import org.deegree.ogcwebservices.wfs.operation.transaction.TransactionResponse;
063: import org.deegree.ogcwebservices.wfs.operation.transaction.Insert.ID_GEN;
064: import org.w3c.dom.Document;
065: import org.w3c.dom.Element;
066: import org.w3c.dom.Node;
067:
068: /**
069: * The <code>InsertTransactionHandler</code> class will cut an csw/wrs ebrim insert transaction into four differend
070: * transactions, some of which are handled as wfs transactions. For each record in an Insert Transaction the basic
071: * workflow is following:
072: * <ol>
073: * <li> find out if the to id of the to inserted record is allready in the wfs database</li>
074: * <li> if so, set it's app:status value to "invalid"</li>
075: * <li> insert / update the records</li>
076: * <li> create an audittrail, that is an app:AuditableEvent of the insertion</li>
077: * </ol>
078: *
079: *
080: * @author <a href="mailto:bezema@lat-lon.de">Rutger Bezema</a>
081: *
082: * @author last edited by: $Author: bezema $
083: *
084: * @version $Revision: 1.7 $, $Date: 2007-06-21 13:54:33 $
085: *
086: */
087:
088: public class InsertTransactionHandler {
089:
090: private static ILogger LOG = LoggerFactory
091: .getLogger(InsertTransactionHandler.class);
092:
093: private Transaction originalTransaction;
094:
095: private Insert insert;
096:
097: private URI appURI;
098:
099: private String userName;
100:
101: /**
102: * Creates an TransactionHandler which will be able to handle csw/ebrim inserts as defined in the wrs spec.
103: *
104: * @param originalTransaction
105: * parsed from the incoming HttpServletRequest.
106: * @param insert
107: * InsertOperation to be handled (as part of the original Transaction) may not be null;
108: * @param appURI
109: * defining a namespace in which the wfs RegistryObjects Recide.
110: * @param userName
111: * of the users which wants to insert registryObjects, if not set it will be set to anonymous.
112: */
113: public InsertTransactionHandler(Transaction originalTransaction,
114: Insert insert, URI appURI, String userName) {
115: if (originalTransaction == null) {
116: throw new InvalidParameterException(
117: "The transaction parameter may not be null");
118: }
119: if (insert == null) {
120: throw new InvalidParameterException(
121: "The insert parameter may not be null");
122: }
123: this .originalTransaction = originalTransaction;
124: this .insert = insert;
125: if (appURI == null) {
126: try {
127: appURI = new URI("http://www.deegree.org/app");
128: } catch (URISyntaxException e) {
129: // nothing to do here.
130: }
131: } else {
132: this .appURI = appURI;
133: }
134: if (userName == null || "".equals(userName)) {
135: userName = "anonymous";
136: }
137: this .userName = userName;
138:
139: }
140:
141: /**
142: * This method will handle the insert (given from
143: *
144: * @param transactionManager
145: * which can handle the csw transactions and allows the access to a localwfs, if null an
146: * InvalidParameterException will be thrown.
147: * @param resultValues
148: * an array[3] in which the number of insertions (resultValues[0]) and/or updates (resultValues[2]) will
149: * be saved. If resultValues.length != 3 an InvalidParameterException will be thrown.
150: * @return the brief representation of the inserted (not updated) elements.
151: * @throws OGCWebServiceException
152: */
153: public List<Element> handleInsertTransaction(
154: Manager transactionManager, int[] resultValues)
155: throws OGCWebServiceException {
156: if (transactionManager == null) {
157: throw new InvalidParameterException(
158: "The transactionManager may not be null");
159: }
160: if (resultValues.length != 3) {
161: throw new InvalidParameterException(
162: "The length of the resultValues array must be 3");
163: }
164:
165: List<Element> records = insert.getRecords();
166:
167: // Some properterypaths which are used for the creation of a complex filter.
168: QualifiedName registryObject = new QualifiedName("app",
169: "RegistryObject", appURI);
170: Expression iduriExpr = new PropertyName(new QualifiedName(
171: "app", "liduri", appURI));
172:
173: Expression statusExpr = new PropertyName(new QualifiedName(
174: "app", "status", appURI));
175: PropertyIsCOMPOperation validOperator = new PropertyIsCOMPOperation(
176: OperationDefines.PROPERTYISEQUALTO, statusExpr,
177: new Literal("valid"));
178:
179: PropertyIsCOMPOperation emptyOperator = new PropertyIsCOMPOperation(
180: OperationDefines.PROPERTYISEQUALTO, statusExpr,
181: new Literal(""));
182: ComplexFilter vFilter = new ComplexFilter(validOperator);
183: ComplexFilter eFilter = new ComplexFilter(emptyOperator);
184: ComplexFilter statusFilter = new ComplexFilter(vFilter,
185: eFilter, OperationDefines.OR);
186:
187: FeatureCollection featureCollectionOnId = null;
188: WFService localWFS = transactionManager.getWfsService();
189:
190: List<Element> briefRecords = new ArrayList<Element>(records
191: .size());
192:
193: /**
194: * Iterate over all records and for each record do the following, <code>
195: * 1) find out if the to id of the to inserted record is allready in the wfs database
196: * 2) if so, set it's app:status value to "invalid"
197: * 3) insert / update the records
198: * 4) create an audittrail, that is an app:AuditableEvent of the insertion
199: * </code>
200: */
201:
202: for (int recordCount = 0; recordCount < records.size(); ++recordCount) {
203: Element record = records.get(recordCount);
204: String auditableEventType = "Created";
205: String oldID = record.getAttribute("id");
206: if (oldID == null || "".equals(oldID)) {
207: throw new OGCWebServiceException(
208: "You are trying to insert a(n) "
209: + record.getNodeName()
210: + " which has no 'id' attribute set, this is a required attribute.");
211: }
212: String predecessorID = oldID;
213: String logicalID = record.getAttribute("lid");
214: if (logicalID == null || "".equals(logicalID)) {
215: // throw new OGCWebServiceException( "You are trying to insert a(n) " + record.getNodeName()
216: // + " which has no 'lid' attribute set, for this registry, this is a required attribute." );
217: LOG
218: .logDebug(" no lid given, setting attribute to value of id");
219: logicalID = oldID;
220: record.setAttribute("lid", oldID);
221: }
222:
223: String home = record.getAttribute("home");
224: if (home == null) {
225: home = "";
226: }
227:
228: // Expression idLiteral = new Literal( oldID );
229: Expression idLiteral = new Literal(logicalID);
230: PropertyIsCOMPOperation idOperator = new PropertyIsCOMPOperation(
231: OperationDefines.PROPERTYISEQUALTO, iduriExpr,
232: idLiteral);
233: ComplexFilter idFilter = new ComplexFilter(idOperator);
234: ComplexFilter idAndStatusFilter = new ComplexFilter(
235: idFilter, statusFilter, OperationDefines.AND);
236: try {
237: //FeatureResult fr = sendWFSGetFeature( localWFS, registryObject, idFilter );
238: FeatureResult fr = sendWFSGetFeature(localWFS,
239: registryObject, idAndStatusFilter);
240: if (fr != null) {
241: featureCollectionOnId = (FeatureCollection) fr
242: .getResponse();
243: }
244: } catch (OGCWebServiceException e) {
245: throw new OGCWebServiceException("The insertion of "
246: + record.getNodeName() + " failed because: "
247: + e.getMessage());
248: }
249: if (featureCollectionOnId == null
250: || "".equals(featureCollectionOnId)) {
251: throw new OGCWebServiceException("The insertion of "
252: + record.getNodeName() + " failed.");
253: }
254:
255: String lockId = featureCollectionOnId
256: .getAttribute("lockId");
257: LOG.logDebug(" InsertHandler, the GetFeature lock is: "
258: + lockId);
259: if (lockId == null || "".equals(lockId)) {
260: throw new OGCWebServiceException(
261: "Couldn't get a lock for "
262: + record.getNodeName()
263: + ". This object can therefore not be inserted.");
264: }
265: String numbOfFeatures = featureCollectionOnId
266: .getAttribute("numberOfFeatures");
267: int featureCount = 0;
268: try {
269: featureCount = Integer.parseInt(numbOfFeatures);
270: LOG
271: .logDebug(" InsertHandler: the number of features in the GetFeatureWithLock was: "
272: + featureCount);
273: } catch (NumberFormatException nfe) {
274: // nottin
275: }
276: // Check the number of hits we've found, if the id allready exists it means we want to set the status of the
277: // object to invalid.
278: // String newID = id;
279: if (featureCount > 1) {
280: throw new OGCWebServiceException(
281: "The lid of this element: "
282: + record.getNodeName()
283: + " is not unique. This object can therefore not be inserted.");
284: } else if (featureCount == 1) {
285: int totalUpdated = changeStatusOfObject(lockId,
286: registryObject, idAndStatusFilter, record
287: .getNodeName(), localWFS);
288:
289: Feature f = featureCollectionOnId.getFeature(0);
290: if (f == null) {
291: LOG.logError("No feature found!!!!!");
292: } else {
293: FeatureProperty iduriProperty = f
294: .getDefaultProperty(new QualifiedName(
295: "app", "iduri", appURI));
296: if (iduriProperty == null) {
297: LOG
298: .logError("The id of this element: "
299: + record.getNodeName()
300: + " is not found in the registry. No association of type 'predecessor' will be inserted!.");
301: } else {
302: predecessorID = (String) iduriProperty
303: .getValue();
304: if (predecessorID == null
305: || "".equals(predecessorID.trim())) {
306: LOG
307: .logError("The registry helds an id of this element: "
308: + record.getNodeName()
309: + " but it is empty. An association of type 'predecessor' will be inserted with to the oldID!.");
310: predecessorID = oldID;
311: } else {
312: LOG
313: .logDebug(" setting predecessorID to id of the registry ("
314: + predecessorID + ").");
315: }
316: LOG
317: .logDebug(" wcsFilter: total updated wfs:records (should be >= 1) = "
318: + totalUpdated);
319: if (totalUpdated == 1) {
320: auditableEventType = "Versioned";
321: }
322: }
323: }
324: }
325:
326: // send the insertion to wcs and insert the auditable event
327:
328: String newID = UUID.randomUUID().toString();
329:
330: if ("Versioned".equals(auditableEventType)) {
331: record.setAttribute("id", newID);
332: }
333:
334: List<Element> tmpRecords = new ArrayList<Element>(1);
335: tmpRecords.add(record);
336:
337: Insert ins = new Insert(insert.getHandle(), tmpRecords);
338: List<Operation> tmpOp = new ArrayList<Operation>(1);
339: tmpOp.add(ins);
340: Transaction transaction = new Transaction(
341: originalTransaction.getVersion(),
342: originalTransaction.getId(), originalTransaction
343: .getVendorSpecificParameters(), tmpOp,
344: false);
345: TransactionResult tmpInsertResult = null;
346: try {
347: tmpInsertResult = transactionManager
348: .transaction(transaction);
349: } catch (OGCWebServiceException ogws) {
350: throw new OGCWebServiceException(
351: "CSW Insert Transaction: Error while inserting '"
352: + record.getNodeName() + "' with id='"
353: + oldID + "' because: "
354: + ogws.getMessage());
355: }
356:
357: if (tmpInsertResult == null
358: || tmpInsertResult.getTotalInserted() != 1) {
359: throw new OGCWebServiceException(
360: "The insertion of the element: "
361: + record.getNodeName()
362: + " failed, because the transactionresult is null or the number of inserted objects wasn't 1.");
363: }
364:
365: if (featureCount == 1) {
366: // update
367: resultValues[2]++;
368: } else {
369: // insert
370: resultValues[0]++;
371: }
372: // First create the necessary Features
373: List<Feature> newObjectsInDB = new ArrayList<Feature>();
374: newObjectsInDB.add(createAuditableEvent(localWFS, oldID,
375: home, auditableEventType, userName));
376: if ("Versioned".equals(auditableEventType)) {
377: newObjectsInDB.add(createAssociation(localWFS, newID,
378: predecessorID));
379:
380: // Now update all following associations which referenced the oldID.
381: for (int i = (recordCount + 1); i < records.size(); ++i) {
382: Element tmpRec = records.get(i);
383: if (CommonNamespaces.OASIS_EBRIMNS.toASCIIString()
384: .equals(tmpRec.getNamespaceURI())
385: && "Association".equals(tmpRec
386: .getLocalName())) {
387: String sourceObject = tmpRec
388: .getAttribute("sourceObject");
389: String targetObject = tmpRec
390: .getAttribute("targetObject");
391: if (oldID.equals(sourceObject)) {
392: LOG
393: .logDebug(" Updating 'rim:Association/@sourceObject' Attribute to new id: "
394: + newID
395: + " after an update of registryObject: "
396: + record.getLocalName());
397: tmpRec.setAttribute("sourceObject", newID);
398: }
399: if (oldID.equals(targetObject)) {
400: LOG
401: .logDebug(" Updating 'rim:Association/@targetObject' Attribute to new id: "
402: + newID
403: + " after an update of registryObject: "
404: + record.getLocalName());
405: tmpRec.setAttribute("targetObject", newID);
406: }
407: }
408: }
409: }
410: insertFeatures(localWFS, newObjectsInDB, record
411: .getNodeName());
412: // sendAuditableEvent( transactionManager.getWfsService(), record.getNodeName(), auditableEventType,
413: // username,
414: // id, home );
415: // create a brief record description of the inserted record.
416: briefRecords.add(generateBriefRecord(record));
417: }
418: return briefRecords;
419: }
420:
421: /**
422: *
423: * @param localWFS
424: * @param registryObject
425: * @param filter
426: * @return the FeatureResult of the given filter or <code>null</code> if something went wrong.
427: * @throws OGCWebServiceException
428: */
429: private FeatureResult sendWFSGetFeature(WFService localWFS,
430: QualifiedName registryObject, ComplexFilter filter)
431: throws OGCWebServiceException {
432: Query q = Query.create(registryObject, filter);
433: GetFeatureWithLock gfwl = GetFeatureWithLock.create("1.1.0",
434: "0", "no_handle", RESULT_TYPE.RESULTS,
435: "text/xml; subtype=gml/3.1.1", -1, 0, -1, -1,
436: new Query[] { q }, null, 300000l, ALL_SOME_TYPE.ALL);
437: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
438: try {
439: GetFeatureDocument gd = XMLFactory.export(gfwl);
440: LOG.logDebug("The getFeature with lock request: "
441: + gd.getAsPrettyString());
442: } catch (IOException e) {
443: LOG
444: .logError("InsertTransactionHandler: An error occurred while trying to get a debugging output for the generated GetFeatureDocument: "
445: + e.getMessage());
446: } catch (XMLParsingException e) {
447: LOG
448: .logError("InsertTransactionHandler: An error occurred while trying to get a debugging output for the generated GetFeatureDocument: "
449: + e.getMessage());
450: }
451: }
452:
453: Object response = localWFS.doService(gfwl);
454: if (response instanceof FeatureResult) {
455: LOG
456: .logDebug("InsertHandler tried to get A feature with Lock, with a valid response from the localwfs");
457: return (FeatureResult) response;
458: }
459: return null;
460: }
461:
462: /**
463: * This method will create a WFSTransaction containing one update operation, which will set the app:status of the
464: * app:RegistryObject found using the complexFilter to superseded.
465: *
466: * @param newId
467: * of the registryObject
468: * @param lockId
469: * which was set while querying the app:RegistryObject for it's app:status
470: * @return the number of updated records, this value should only be 1 or 0.
471: * @throws OGCWebServiceException
472: * if something went wrong.
473: */
474: private int changeStatusOfObject(String lockId,
475: QualifiedName registryObject, ComplexFilter filter,
476: String originalRecordNodeName, WFService localWFS)
477: throws OGCWebServiceException {
478: List<TransactionOperation> operations = new ArrayList<TransactionOperation>();
479: Map<PropertyPath, FeatureProperty> properties = new HashMap<PropertyPath, FeatureProperty>();
480:
481: // the new status value, e.g. app:RegistryObject/app:status=invalid
482: QualifiedName status = new QualifiedName("app", "status",
483: appURI);
484: PropertyPath statusPP = PropertyPathFactory
485: .createPropertyPath(registryObject);
486: statusPP.append(PropertyPathFactory
487: .createPropertyPathStep(status));
488:
489: // // the new id value e.g app:RegistryObject/app:iduri=newId
490: // QualifiedName iduri = new QualifiedName( "app", "iduri", appURI );
491: // PropertyPath iduriPP = PropertyPathFactory.createPropertyPath( registryObject );
492: // iduriPP.append( PropertyPathFactory.createAttributePropertyPathStep( iduri ) );
493:
494: // Adding the properties (e.g. the status=ivalid and the iduri=newId) to the wfs:UpdateOperation.
495: properties.put(statusPP, FeatureFactory.createFeatureProperty(
496: status, "superseded"));
497: // properties.put( iduriPP, FeatureFactory.createFeatureProperty( iduri, newId ) );
498:
499: operations
500: .add(new org.deegree.ogcwebservices.wfs.operation.transaction.Update(
501: "no_handle", registryObject, properties, filter));
502: org.deegree.ogcwebservices.wfs.operation.transaction.Transaction wfsTransaction = new org.deegree.ogcwebservices.wfs.operation.transaction.Transaction(
503: "0", "1.1.0", null, lockId, operations, true, null);
504: int totalUpdated = 0;
505: try {
506: Object response = localWFS.doService(wfsTransaction);
507: if (response instanceof TransactionResponse) {
508: totalUpdated = ((TransactionResponse) response)
509: .getTotalUpdated();
510: }
511: } catch (OGCWebServiceException e) {
512: throw new OGCWebServiceException("The insertion of "
513: + originalRecordNodeName + " failed: "
514: + e.getMessage());
515: }
516: return totalUpdated;
517:
518: }
519:
520: /**
521: * creates a brief representation of the given RegistryObject element, with following values (wrs spec):
522: * <ul>
523: * <li>rim:RegistryObject/@id</li>
524: * <li>rim:RegistryObject/@lid</li>
525: * <li>rim:RegistryObject/@objectType</li>
526: * <li>rim:RegistryObject/@status</li>
527: * <li>rim:RegistryObject/rim:VersionInfo</li>
528: * </ul>
529: *
530: * @return a brief record description of the given ebrim:RegistryObject
531: */
532: private Element generateBriefRecord(Element record) {
533: Document doc = XMLTools.create();
534: Element resultElement = doc.createElement("csw:result");
535: Element a = (Element) doc.importNode(record, false);
536: resultElement.appendChild(a);
537: List<Node> attribs = null;
538: try {
539: attribs = XMLTools.getNodes(a, "./@*", CommonNamespaces
540: .getNamespaceContext());
541: } catch (XMLParsingException e1) {
542: LOG
543: .logError(
544: "InsertTransactionHandler: an error occurred while creating a briefrecord for registryObject: "
545: + record.getNodeName(), e1);
546: }
547: // NamedNodeMap attribs = a.getAttributes();
548: if (attribs != null) {
549: for (Node attribute : attribs) {
550: // Attr attribute = (Attr) attribs.item( i );
551: String localName = attribute.getLocalName();
552:
553: LOG.logDebug("From: " + a.getNodeName()
554: + " found attribute (localname): " + localName);
555: if (!("id".equals(localName) || "lid".equals(localName)
556: || "objectType".equals(localName) || "status"
557: .equals(localName))) {
558: // resultElement.setAttributeNode( (Attr)attribs.item(i) );
559: LOG.logDebug(" From: " + a.getNodeName()
560: + " removing attribute (localname): "
561: + localName);
562: String namespace = attribute.getBaseURI();
563: // a.removeChild( attribs.item(i) );
564: a.removeAttributeNS(namespace, localName);
565: }
566: }
567: }
568: Element versionInfo = null;
569: try {
570: versionInfo = XMLTools.getElement(record,
571: "rim:VersionInfo", CommonNamespaces
572: .getNamespaceContext());
573: if (versionInfo != null) {
574: Node vi = doc.importNode(versionInfo, true);
575: a.appendChild(vi);
576: }
577: } catch (XMLParsingException e) {
578: LOG
579: .logError(
580: "InsertTransactionHandler: an error occurred while creating a briefrecord for registryObject: "
581: + record.getNodeName(), e);
582: }
583: return a;
584: }
585:
586: /**
587: * Creates an association of type "urn:adv:registry:AssociationType:predecessor" which associates an old
588: * (updated/superseded) registry object with a new registry object.
589: *
590: * @param localWFS
591: * which will be talked to directly (superseding the csw).
592: * @param newRegisterID
593: * the id of the new object inserted in the db
594: * @param oldRegisterID
595: * the id of the old updated object, superseded in the db
596: */
597: private Feature createAssociation(WFService localWFS,
598: String newRegisterID, String oldRegisterID) {
599:
600: QualifiedName registryObject = new QualifiedName("app",
601: "RegistryObject", appURI);
602: QualifiedName associationType = new QualifiedName("app",
603: "Association", appURI);
604:
605: MappedFeatureType rootFT = localWFS
606: .getMappedFeatureType(registryObject);
607: MappedFeatureType associationFT = localWFS
608: .getMappedFeatureType(associationType);
609:
610: List<FeatureProperty> featureProperties = new ArrayList<FeatureProperty>();
611:
612: // Generate the Auditable Event complex subfeature
613:
614: QualifiedName associationTypeProp = new QualifiedName("app",
615: "associationType", appURI);
616: featureProperties.add(FeatureFactory.createFeatureProperty(
617: associationTypeProp,
618: "urn:adv:registry:AssociationType:predecessor"));
619:
620: QualifiedName sourceObject = new QualifiedName("app",
621: "sourceObject", appURI);
622: featureProperties.add(FeatureFactory.createFeatureProperty(
623: sourceObject, newRegisterID));
624:
625: QualifiedName targetObject = new QualifiedName("app",
626: "targetObject", appURI);
627: featureProperties.add(FeatureFactory.createFeatureProperty(
628: targetObject, oldRegisterID));
629:
630: Feature associationFeature = FeatureFactory.createFeature(null,
631: associationFT, featureProperties);
632:
633: // Creation of the RegistryObject
634: featureProperties.clear();
635:
636: // type
637: QualifiedName type = new QualifiedName("app", "type", appURI);
638: featureProperties.add(FeatureFactory.createFeatureProperty(
639: type, "Association"));
640:
641: QualifiedName iduri = new QualifiedName("app", "iduri", appURI);
642: featureProperties.add(FeatureFactory.createFeatureProperty(
643: iduri, UUID.randomUUID().toString()));
644:
645: // objecttype
646: QualifiedName objectType = new QualifiedName("app",
647: "objectType", appURI);
648: featureProperties
649: .add(FeatureFactory
650: .createFeatureProperty(objectType,
651: "urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:Association"));
652:
653: // status
654: QualifiedName status = new QualifiedName("app", "status",
655: appURI);
656: featureProperties.add(FeatureFactory.createFeatureProperty(
657: status, "valid"));
658:
659: // create the auditable Event property with the feature
660: QualifiedName association = new QualifiedName("app",
661: "association", appURI);
662: featureProperties.add(FeatureFactory.createFeatureProperty(
663: association, associationFeature));
664:
665: Feature rootFeature = FeatureFactory.createFeature(null,
666: rootFT, featureProperties);
667: return rootFeature;
668: }
669:
670: /**
671: * Creates an auditable event for the given objectid
672: *
673: * TODO shouldn't the slots of the original inserted Object not be handled?
674: *
675: * @param localWFS
676: * which will be talked to directly (superseding the csw).
677: * @param affectedObjectId
678: * of the object which has been inserted or updated
679: * @param affectedHome
680: * of the object which has been inserted or updated
681: * @param auditEventType
682: * should be one of 'Created' or 'Updated' (see the ebrim spec)
683: * @param username
684: * of the person doing the insertion
685: */
686: private Feature createAuditableEvent(WFService localWFS,
687: String affectedObjectId, String affectedHome,
688: String auditEventType, String username) {
689: String requestId = originalTransaction.getId();
690:
691: QualifiedName registryObject = new QualifiedName("app",
692: "RegistryObject", appURI);
693: QualifiedName auditableEventType = new QualifiedName("app",
694: "AuditableEvent", appURI);
695: QualifiedName objectRefType = new QualifiedName("app",
696: "ObjectRef", appURI);
697:
698: MappedFeatureType rootFT = localWFS
699: .getMappedFeatureType(registryObject);
700: MappedFeatureType auditableEventFT = localWFS
701: .getMappedFeatureType(auditableEventType);
702: MappedFeatureType objectRefFT = localWFS
703: .getMappedFeatureType(objectRefType);
704:
705: List<FeatureProperty> featureProperties = new ArrayList<FeatureProperty>();
706:
707: // Creating the Objectref
708: QualifiedName replacedURI = new QualifiedName("app", "iduri",
709: appURI);
710: featureProperties.add(FeatureFactory.createFeatureProperty(
711: replacedURI, affectedObjectId));
712:
713: QualifiedName replacedHome = new QualifiedName("app", "home",
714: appURI);
715: featureProperties.add(FeatureFactory.createFeatureProperty(
716: replacedHome, affectedHome));
717:
718: QualifiedName createReplica = new QualifiedName("app",
719: "createReplica", appURI);
720: featureProperties.add(FeatureFactory.createFeatureProperty(
721: createReplica, "false"));
722:
723: Feature objectRefFeature = FeatureFactory.createFeature(null,
724: objectRefFT, featureProperties);
725:
726: // Generate the Auditable Event complex subfeature
727: featureProperties.clear();
728:
729: QualifiedName eventType = new QualifiedName("app", "eventType",
730: appURI);
731: featureProperties.add(FeatureFactory.createFeatureProperty(
732: eventType, auditEventType));
733:
734: QualifiedName timestamp = new QualifiedName("app", "timestamp",
735: appURI);
736: featureProperties.add(FeatureFactory.createFeatureProperty(
737: timestamp, TimeTools.getISOFormattedTime()));
738:
739: QualifiedName usernameQName = new QualifiedName("app",
740: "username", appURI);
741: featureProperties.add(FeatureFactory.createFeatureProperty(
742: usernameQName, username));
743:
744: QualifiedName requestIdQName = new QualifiedName("app",
745: "requestId", appURI);
746: featureProperties.add(FeatureFactory.createFeatureProperty(
747: requestIdQName, requestId));
748:
749: // add the affected ObjectsFeatureType to the affectedObjects property
750: QualifiedName affectedObjects = new QualifiedName("app",
751: "affectedObjects", appURI);
752: featureProperties.add(FeatureFactory.createFeatureProperty(
753: affectedObjects, objectRefFeature));
754:
755: Feature auditEventFeature = FeatureFactory.createFeature(null,
756: auditableEventFT, featureProperties);
757:
758: // Creation of the RegistryObject
759: featureProperties.clear();
760:
761: // type
762: QualifiedName type = new QualifiedName("app", "type", appURI);
763: featureProperties.add(FeatureFactory.createFeatureProperty(
764: type, "AuditableEvent"));
765:
766: QualifiedName iduri = new QualifiedName("app", "iduri", appURI);
767: featureProperties.add(FeatureFactory.createFeatureProperty(
768: iduri, UUID.randomUUID().toString()));
769:
770: // objecttype
771: QualifiedName objectType = new QualifiedName("app",
772: "objectType", appURI);
773: featureProperties
774: .add(FeatureFactory
775: .createFeatureProperty(objectType,
776: "urn:oasis:names:tc:ebxml-regrep:ObjectType:RegistryObject:AuditableEvent"));
777:
778: // status
779: QualifiedName status = new QualifiedName("app", "status",
780: appURI);
781: featureProperties.add(FeatureFactory.createFeatureProperty(
782: status, "valid"));
783:
784: // create the auditable Event property with the feature
785: QualifiedName auditableEvent = new QualifiedName("app",
786: "auditableEvent", appURI);
787: featureProperties.add(FeatureFactory.createFeatureProperty(
788: auditableEvent, auditEventFeature));
789:
790: Feature rootFeature = FeatureFactory.createFeature(null,
791: rootFT, featureProperties);
792:
793: return rootFeature;
794: }
795:
796: /**
797: * Puts an auditable event for the given objectid into the database, thus resulting in an AuditTrail for the
798: * inserted/updated Object.
799: *
800: *
801: * @param localWFS
802: * which will be talked to directly (superseding the csw).
803: * @param featuresToInsert
804: * an array of features (either an auditableEvent or an auditableEvent and an Association (if an update
805: * occurred) ).
806: * @param originalInsertObjectName
807: * the name of the object to be inserted (used for debug messages)
808: * @throws OGCWebServiceException
809: */
810: private void insertFeatures(WFService localWFS,
811: List<Feature> featuresToInsert,
812: String originalInsertObjectName)
813: throws OGCWebServiceException {
814: String requestId = originalTransaction.getId();
815: if (featuresToInsert.size() == 0) {
816: LOG
817: .logError("CSW (Ebrim) InsertTransactionHandler: there were no features to insert, this may not be (at least an auditableEvent feature should be inserted)!");
818: return;
819: }
820: Feature[] fA = new Feature[featuresToInsert.size()];
821: for (int i = 0; i < fA.length; ++i) {
822: fA[i] = featuresToInsert.get(i);
823: }
824: FeatureCollection fc = FeatureFactory.createFeatureCollection(
825: requestId, fA);
826:
827: org.deegree.ogcwebservices.wfs.operation.transaction.Insert wfsInsert = new org.deegree.ogcwebservices.wfs.operation.transaction.Insert(
828: "no_handle", ID_GEN.GENERATE_NEW, null, fc);
829: List<TransactionOperation> ops = new ArrayList<TransactionOperation>(
830: 1);
831: ops.add(wfsInsert);
832: org.deegree.ogcwebservices.wfs.operation.transaction.Transaction transaction = new org.deegree.ogcwebservices.wfs.operation.transaction.Transaction(
833: originalTransaction.getId(), "1.1.0", null, null, ops,
834: true, null);
835:
836: try {
837: localWFS.doService(transaction);
838: } catch (OGCWebServiceException e) {
839: String features = "AuditableEvent ";
840: if (fA.length > 1)
841: features += "and an Association ";
842: throw new OGCWebServiceException(
843: "Could not insert an "
844: + features
845: + "for the insertion/update of the RegistryObject: "
846: + originalInsertObjectName + " because: "
847: + e.getMessage());
848: }
849:
850: if (LOG.getLevel() == ILogger.LOG_DEBUG) {
851: try {
852: TransactionDocument doc = XMLFactory
853: .export(transaction);
854: LOG
855: .logDebug(" The auditable event created for the insertion of '"
856: + originalInsertObjectName
857: + "' is:\n"
858: + doc.getAsPrettyString());
859: } catch (IOException e) {
860: LOG
861: .logError("InsertTransactionHandler: An error occurred while trying to create an auditable Event for insertion of the '"
862: + originalInsertObjectName
863: + "'. Errormessage: " + e.getMessage());
864: } catch (XMLParsingException e) {
865: LOG
866: .logError("InsertTransactionHandler: An error occurred while trying to create an auditable Event for insertion of the '"
867: + originalInsertObjectName
868: + "'. Errormessage: " + e.getMessage());
869: }
870: }
871:
872: }
873:
874: }
|