/**
   * Obtain values from XML an create value object ContentRelation.
   *
   * @param xml The content relation XML (validated by schema).
   * @return ContentRelation
   * @throws InvalidContentException Thrown if content is invalid
   * @throws MissingAttributeValueException Thrown if attribute value is missing
   * @throws SystemException Thrown if internal error occur
   * @throws de.escidoc.core.common.exceptions.application.invalid.XmlCorruptedException
   */
  private static ContentRelationCreate parseContentRelation(final String xml)
      throws MissingAttributeValueException, InvalidContentException, SystemException,
          XmlCorruptedException {

    final StaxParser sp = new StaxParser();

    final ContentRelationHandler contentRelationHandler = new ContentRelationHandler(sp);
    sp.addHandler(contentRelationHandler);

    try {
      sp.parse(xml);
    } catch (final InvalidContentException e) {
      throw new InvalidContentException(e.getMessage(), e);
    } catch (final RelationPredicateNotFoundException e) {
      // shouldn't happen
      throw new SystemException(e);
    } catch (final XmlCorruptedException e) {
      throw new XmlCorruptedException(e.getMessage(), e);
    } catch (final MissingAttributeValueException e) {
      throw new MissingAttributeValueException(e.getMessage(), e);
    } catch (final InvalidStatusException e) {
      // shouldn't happen
      throw new SystemException(e);
    } catch (final SystemException e) {
      throw new SystemException(null, e);
    } catch (final Exception e) {
      XmlUtility.handleUnexpectedStaxParserException(null, e);
    }
    return contentRelationHandler.getContentRelation();
  }
  /**
   * See Interface for functional description.
   *
   * @param xmlData aggregationDefinition as xml in aggregationDefinition schema.
   * @return Returns the XML representation of the resource.
   * @throws MissingMethodParameterException ex
   * @throws ScopeNotFoundException ex
   * @throws SystemException ex
   * @see de.escidoc.core.sm.business.interfaces
   *     .AggregationDefinitionHandlerInterface#create(java.lang.String)
   */
  @Override
  @Transactional(rollbackFor = {SystemException.class, RuntimeException.class})
  public String create(final String xmlData)
      throws MissingMethodParameterException, ScopeNotFoundException, SystemException {
    if (xmlData == null || xmlData.length() == 0) {
      throw new MissingMethodParameterException("xml may not be null");
    }

    // parse
    final StaxParser sp = new StaxParser();
    final AggregationDefinitionStaxHandler handler = new AggregationDefinitionStaxHandler(sp);
    sp.addHandler(handler);
    try {
      sp.parse(xmlData);
    } catch (final Exception e) {
      throw new SystemException(e);
    }

    final String scopeId = handler.getAggregationDefinition().getScope().getId();
    final Scope scope = scopesDao.retrieve(scopeId);

    // get AggregationDefinitionObject to insert aggregation-definition
    // into database
    final AggregationDefinition aggregationDefinition = handler.getAggregationDefinition();
    aggregationDefinition.setCreatorId(utility.getCurrentUserId());
    aggregationDefinition.setCreationDate(new Timestamp(System.currentTimeMillis()));
    aggregationDefinition.setScope(scope);

    dao.save(aggregationDefinition);
    handler.setAggregationDefinition(aggregationDefinition);

    // AggregationStatisticDataSelectors
    for (final AggregationStatisticDataSelector selector :
        handler.getAggregationStatisticDataSelectors()) {
      dao.save(selector);
    }
    aggregationDefinition.setAggregationStatisticDataSelectors(
        handler.getAggregationStatisticDataSelectors());

    // AggregationTables
    for (final AggregationTable aggregationTable : handler.getAggregationTables()) {
      dao.save(aggregationTable);
    }
    aggregationDefinition.setAggregationTables(handler.getAggregationTables());

    // Get databaseTableVos for all Aggregation-Tables
    // defined in Aggregation Definition
    final Collection<DatabaseTableVo> databaseTableVos =
        generateAggregationDatabaseTableVos(aggregationDefinition);
    if (databaseTableVos != null) {
      for (final DatabaseTableVo databaseTableVo : databaseTableVos) {
        // create aggregation table in Database
        dbAccessor.createTable(databaseTableVo);
      }
    }

    return renderer.render(aggregationDefinition);
  }
  /**
   * Retrieve the properties of the last version (RELS-EXT) and inject values into
   * ContentRelationCreate object.
   *
   * @param cr ContentRelation object
   * @throws SystemException Thrown in case of internal failure.
   * @throws ContentRelationNotFoundException Thrown if resource with provided id could not be found
   *     in Fedora repository.
   */
  private static void setRelsExtValues(final ContentRelationCreate cr)
      throws SystemException, ContentRelationNotFoundException {

    // retrieve resource with id from Fedora
    final Datastream relsExt;
    try {
      relsExt = new Datastream(Datastream.RELS_EXT_DATASTREAM, cr.getObjid(), null);
    } catch (final StreamNotFoundException e) {
      throw new ContentRelationNotFoundException(
          "Content Relation with id '" + cr.getObjid() + "' could not be found.", e);
    }

    final StaxParser sp = new StaxParser();

    final RelsExtReadHandler eve = new RelsExtReadHandler(sp);
    eve.cleanIdentifier(true);
    sp.addHandler(eve);
    try {
      sp.parse(relsExt.getStream());
    } catch (final Exception e) {
      throw new WebserverSystemException(e);
    }

    final List<Triple> triples = eve.getElementValues().getTriples();

    // write triple values into ContentRelation object

    for (final Triple triple : triples) {
      if (triple.getPredicate().equals(TripleStoreUtility.PROP_FRAMEWORK_BUILD)) {
        cr.setBuildNumber(triple.getObject());
      }
      // creator --------------
      else if (triple.getPredicate().equals(TripleStoreUtility.PROP_CREATED_BY_ID)) {
        cr.getProperties().setCreatedById(triple.getObject());
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_CREATED_BY_TITLE)) {
        cr.getProperties().setCreatedByName(triple.getObject());
      }
      // modifier --------------
      else if (triple.getPredicate().equals(TripleStoreUtility.PROP_MODIFIED_BY_ID)) {
        cr.getProperties().setModifiedById(triple.getObject());
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_MODIFIED_BY_TITLE)) {
        cr.getProperties().setModifiedByName(triple.getObject());
      }
      // public-status --------------
      else if (triple.getPredicate().equals(TripleStoreUtility.PROP_PUBLIC_STATUS)) {

        final StatusType st;
        try {
          st = StatusType.getStatusType(triple.getObject());
        } catch (final InvalidStatusException e) {
          // shouldn't happen
          throw new SystemException(e);
        }
        cr.getProperties().setStatus(st);
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_PUBLIC_STATUS_COMMENT)) {
        cr.getProperties().setStatusComment(triple.getObject());
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_OBJECT_TYPE)) {
        // this is not the ContentRelation type, this is the type of
        // resource
        if (!(Constants.CONTENT_RELATION2_OBJECT_TYPE.equals(triple.getObject())
            || (Constants.RDF_NAMESPACE_URI + "Statement").equals(triple.getObject()))) {
          throw new WebserverSystemException("Resource is not from type ContentRelation.");
        }
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_CONTENT_RELATION_SUBJECT)) {
        cr.setSubject(triple.getObject());
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_CONTENT_RELATION_OBJECT)) {
        cr.setObject(triple.getObject());
      } else if (triple
          .getPredicate()
          .equals(TripleStoreUtility.PROP_CONTENT_RELATION_DESCRIPTION)) {
        cr.getProperties().setDescription(triple.getObject());
      } else if (triple.getPredicate().equals(TripleStoreUtility.PROP_CONTENT_RELATION_TYPE)) {
        try {
          cr.setType(new URI(triple.getObject()));
        } catch (final URISyntaxException e) {
          // shouldn't happen
          throw new SystemException("Stored value for URI in invalid.", e);
        }
      } else if (triple
          .getPredicate()
          .equals(TripleStoreUtility.PROP_CONTENT_RELATION_OBJECT_VERSION)) {
        cr.setObjectVersion(triple.getObject());
      } else {
        // add values for mapping
        LOGGER.warn("Predicate not mapped " + triple.getPredicate() + " = " + triple.getObject());
      }
    }
  }