/**
   * @param request
   * @param xml
   * @param context
   * @param toIndex
   * @return
   * @throws Exception
   */
  private int updateTransaction(
      Element request, Element xml, ServiceContext context, Set<String> toIndex) throws Exception {
    GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME);
    DataManager dataMan = gc.getDataManager();

    if (context.getUserSession().getUserId() == null)
      throw new NoApplicableCodeEx("User not authenticated.");

    int totalUpdated = 0;

    // Update full metadata
    if (xml != null) {

      // Retrieve schema and the related Namespaces
      String schemaId = gc.getSchemamanager().autodetectSchema(xml);

      if (schemaId == null) {
        throw new NoApplicableCodeEx("Can't identify metadata schema");
      }

      // Retrieve the metadata identifier
      Dbms dbms = (Dbms) context.getResourceManager().open(Geonet.Res.MAIN_DB);

      String uuid = gc.getDataManager().extractUUID(schemaId, xml);

      if (uuid.length() == 0) {
        throw new NoApplicableCodeEx("Metadata identifier not provided");
      }

      // Update metadata record
      String id = dataMan.getMetadataId(dbms, uuid);

      if (id == null) return totalUpdated;

      if (!gc.getAccessManager().canEdit(context, id))
        throw new NoApplicableCodeEx("User not allowed to update this metadata(" + id + ").");

      String changeDate = null;

      boolean validate = false;
      boolean ufo = false;
      boolean index = false;
      String language = context.getLanguage();
      dataMan.updateMetadata(
          context, dbms, id, xml, validate, ufo, index, language, changeDate, false);

      dbms.commit();
      toIndex.add(id);

      totalUpdated++;

      return totalUpdated;

      // Update properties
    } else {
      // first, search the record in the database to get the record id
      Element constr = (Element) request.getChild("Constraint", Csw.NAMESPACE_CSW).clone();
      List<Element> results = getResultsFromConstraints(context, constr);

      List<Element> recordProperties =
          (List<Element>) request.getChildren("RecordProperty", Csw.NAMESPACE_CSW);

      Iterator<Element> it = results.iterator();
      if (!it.hasNext()) return totalUpdated;

      Dbms dbms = (Dbms) context.getResourceManager().open(Geonet.Res.MAIN_DB);

      Set updatedMd = new HashSet<String>();
      // Process all records selected
      while (it.hasNext()) {
        Element result = it.next();
        String uuid = result.getChildText("identifier", Csw.NAMESPACE_DC);
        String id = dataMan.getMetadataId(dbms, uuid);
        String changeDate = null;

        if (id == null) continue;

        if (!dataMan.getAccessManager().canEdit(context, id))
          throw new NoApplicableCodeEx("User not allowed to update this metadata(" + id + ").");

        Element metadata = dataMan.getMetadata(context, id, false, false, true);
        metadata.removeChild("info", Edit.NAMESPACE);

        // Retrieve the schema and Namespaces of metadata to update
        String schemaId = gc.getDataManager().autodetectSchema(metadata);

        if (schemaId == null) {
          throw new NoApplicableCodeEx("Can't identify metadata schema");
        }

        Map mapNs = retrieveNamepacesForSchema(gc.getDataManager().getSchema(schemaId));

        boolean metadataChanged = false;

        // Process properties to update
        for (Element recordProperty : recordProperties) {
          Element propertyNameEl = recordProperty.getChild("Name", Csw.NAMESPACE_CSW);
          Element propertyValueEl = recordProperty.getChild("Value", Csw.NAMESPACE_CSW);

          String propertyName = propertyNameEl.getText();

          String propertyValue = propertyValueEl.getText();

          // Get XPath for queriable name, i provided in propertyName.
          // Otherwise assume propertyName contains full XPath to property to update
          String xpathProperty = FieldMapper.mapXPath(propertyName, schemaId);
          if (xpathProperty == null) {
            xpathProperty = propertyName;
          }

          Log.info(Geonet.CSW, "Xpath of property: " + xpathProperty);
          XPath xpath = new JDOMXPath(xpathProperty);
          xpath.setNamespaceContext(new SimpleNamespaceContext(mapNs));

          Object propEl = xpath.selectSingleNode(metadata);
          Log.info(Geonet.CSW, "XPath found in metadata: " + (propEl != null));

          // If a property is not found in metadata, just ignore it.
          if (propEl != null) {
            if (propEl instanceof Element) {
              ((Element) propEl).setText(propertyValue);
              metadataChanged = true;

            } else if (propEl instanceof Attribute) {
              ((Attribute) propEl).setValue(propertyValue);
              metadataChanged = true;
            }
          }
        } // for(Element recordProperty : recordProperties)

        // Update the metadata with changes
        if (metadataChanged) {
          boolean validate = false;
          boolean ufo = false;
          boolean index = false;
          String language = context.getLanguage();
          dataMan.updateMetadata(
              context, dbms, id, metadata, validate, ufo, index, language, changeDate, false);

          updatedMd.add(id);

          totalUpdated++;
        }
      }
      dbms.commit();
      toIndex.addAll(updatedMd);

      return totalUpdated;
    }
  }
  public Element exec(Element params, ServiceContext context) throws Exception {
    GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME);
    DataManager dm = gc.getDataManager();
    AccessManager am = gc.getAccessManager();

    Dbms dbms = (Dbms) context.getResourceManager().open(Geonet.Res.MAIN_DB);

    String id = Utils.getIdentifierFromParameters(params, context);

    // -----------------------------------------------------------------------
    // --- check access

    MdInfo info = dm.getMetadataInfo(dbms, id);

    if (info == null) throw new MetadataNotFoundEx(id);

    Element ownerId = new Element("ownerid").setText(info.owner);
    Element hasOwner = new Element("owner");
    if (am.isOwner(context, id)) hasOwner.setText("true");
    else hasOwner.setText("false");

    // --- get all operations

    Element elOper = Lib.local.retrieve(dbms, "Operations").setName(Geonet.Elem.OPERATIONS);

    // -----------------------------------------------------------------------
    // --- retrieve groups operations

    Set<String> userGroups =
        am.getUserGroups(dbms, context.getUserSession(), context.getIpAddress());

    Element elGroup = Lib.local.retrieve(dbms, "Groups");

    List list = elGroup.getChildren();

    for (int i = 0; i < list.size(); i++) {
      Element el = (Element) list.get(i);

      el.setName(Geonet.Elem.GROUP);

      // --- get all operations that this group can do on given metadata

      String sGrpId = el.getChildText("id");

      el.setAttribute("userGroup", userGroups.contains(sGrpId) ? "true" : "false");

      String query = "SELECT operationId FROM OperationAllowed WHERE metadataId=? AND groupId=?";

      List listAllow = dbms.select(query, id, sGrpId).getChildren();

      // --- now extend the group list adding proper operations

      List listOper = elOper.getChildren();

      for (int j = 0; j < listOper.size(); j++) {
        String operId = ((Element) listOper.get(j)).getChildText("id");
        Element elGrpOper =
            new Element(Geonet.Elem.OPER).addContent(new Element(Geonet.Elem.ID).setText(operId));
        boolean bFound = false;

        for (int k = 0; k < listAllow.size(); k++) {
          Element elAllow = (Element) listAllow.get(k);

          if (operId.equals(elAllow.getChildText("operationid"))) {
            bFound = true;
            break;
          }
        }
        if (bFound) elGrpOper.addContent(new Element(Geonet.Elem.ON));

        el.addContent(elGrpOper);
      }
    }

    // -----------------------------------------------------------------------
    // --- put all together

    Element elRes =
        new Element(Jeeves.Elem.RESPONSE)
            .addContent(new Element(Geonet.Elem.ID).setText(id))
            .addContent(elOper)
            .addContent(elGroup)
            .addContent(ownerId)
            .addContent(hasOwner);

    return elRes;
  }
  /**
   * @param xml
   * @param fileIds
   * @param context
   * @param toIndex
   * @return
   * @throws Exception
   */
  private boolean insertTransaction(
      Element xml, List<String> fileIds, ServiceContext context, Set<String> toIndex)
      throws Exception {
    GeonetContext gc = (GeonetContext) context.getHandlerContext(Geonet.CONTEXT_NAME);
    DataManager dataMan = gc.getDataManager();

    String schema = dataMan.autodetectSchema(xml);

    //		String category   = Util.getParam(request, Params.CATEGORY);
    String category = null, source = null, createDate = null, changeDate = null;

    String uuid;
    uuid = dataMan.extractUUID(schema, xml);
    if (uuid.length() == 0) uuid = UUID.randomUUID().toString();

    // -----------------------------------------------------------------------
    // --- insert metadata into the system

    UserSession us = context.getUserSession();

    if (us.getUserId() == null) throw new NoApplicableCodeEx("User not authenticated.");

    String profile = us.getProfile();

    // Only editors and above are allowed to insert metadata
    if (!profile.equals(Geonet.Profile.EDITOR)
        && !profile.equals(Geonet.Profile.REVIEWER)
        && !profile.equals(Geonet.Profile.USER_ADMIN)
        && !profile.equals(Geonet.Profile.ADMINISTRATOR))
      throw new NoApplicableCodeEx("User not allowed to insert metadata.");

    int userId = us.getUserIdAsInt();

    AccessManager am = gc.getAccessManager();
    Dbms dbms = (Dbms) context.getResourceManager().open(Geonet.Res.MAIN_DB);

    // Set default group: user first group
    Set<String> userGroups = am.getVisibleGroups(dbms, userId);
    String group;
    if (userGroups.isEmpty()) {
      group = null;
    } else {
      group = (String) userGroups.iterator().next();
    }
    //
    // insert metadata
    //
    String docType = null, title = null, isTemplate = null;
    boolean ufo = true, indexImmediate = false;
    String id =
        dataMan.insertMetadata(
            context,
            dbms,
            schema,
            xml,
            context.getSerialFactory().getSerial(dbms, "Metadata"),
            uuid,
            userId,
            group,
            source,
            isTemplate,
            docType,
            title,
            category,
            createDate,
            changeDate,
            ufo,
            indexImmediate);

    if (id == null) return false;

    // Set metadata as public if setting enabled
    SettingManager sm = gc.getSettingManager();
    boolean metadataPublic = sm.getValueAsBool("system/csw/metadataPublic", false);

    if (metadataPublic) {
      dataMan.setOperation(context, dbms, id, "1", AccessManager.OPER_VIEW);
    }

    dataMan.indexMetadata(dbms, id);

    fileIds.add(uuid);

    dbms.commit();
    toIndex.add(id);
    return true;
  }