();
-
- // only get iso19139 records
- for (String childId : children) {
-
- // Check privileges
- if (!accessManager.canEdit(srvContext, childId)) {
- untreatedChildSet.add(childId);
+ return md;
+ }
+ }
+
+ /**
+ * Updates all children of the selected parent. Some elements are protected in
+ * the children according to the stylesheet used in
+ * xml/schemas/[SCHEMA]/update-child-from-parent-info.xsl.
+ *
+ * Children MUST be editable and also in the same schema of the parent. If not,
+ * child is not updated.
+ *
+ * @param srvContext service context
+ * @param parentUuid parent uuid
+ * @param children children
+ * @param params parameters
+ */
+ @Override
+ public Set updateChildren(ServiceContext srvContext, String parentUuid, String[] children,
+ Map params) throws Exception {
+ String parentId = (String) params.get(Params.ID);
+ String parentSchema = (String) params.get(Params.SCHEMA);
+
+ // --- get parent metadata in read/only mode
+ boolean forEditing = false, withValidationErrors = false, keepXlinkAttributes = false;
+ Element parent = getMetadata(srvContext, parentId, forEditing, withValidationErrors, keepXlinkAttributes);
+
+ Element env = new Element("update");
+ env.addContent(new Element("parentUuid").setText(parentUuid));
+ env.addContent(new Element("siteURL").setText(settingManager.getSiteURL(srvContext)));
+ env.addContent(new Element("parent").addContent(parent));
+
+ // Set of untreated children (out of privileges, different schemas)
+ Set untreatedChildSet = new HashSet();
+
+ // only get iso19139 records
+ for (String childId : children) {
+
+ // Check privileges
+ if (!accessManager.canEdit(srvContext, childId)) {
+ untreatedChildSet.add(childId);
LOGGER_DATA_MANAGER.debug("Could not update child ({}) because of privileges.", childId);
- continue;
- }
-
- Element child = getMetadata(srvContext, childId, forEditing, withValidationErrors, keepXlinkAttributes);
-
- String childSchema = child.getChild(Edit.RootChild.INFO, Edit.NAMESPACE)
- .getChildText(Edit.Info.Elem.SCHEMA);
-
- // Check schema matching. CHECKME : this suppose that parent and
- // child are in the same schema (even not profil different)
- if (!childSchema.equals(parentSchema)) {
- untreatedChildSet.add(childId);
- LOGGER_DATA_MANAGER.debug("Could not update child ({}) because schema ({}) is different from the parent one ({}).",
- new Object[] {childId, childSchema, parentSchema});
- continue;
- }
+ continue;
+ }
+
+ Element child = getMetadata(srvContext, childId, forEditing, withValidationErrors, keepXlinkAttributes);
+
+ String childSchema = child.getChild(Edit.RootChild.INFO, Edit.NAMESPACE)
+ .getChildText(Edit.Info.Elem.SCHEMA);
+
+ // Check schema matching. CHECKME : this suppose that parent and
+ // child are in the same schema (even not profil different)
+ if (!childSchema.equals(parentSchema)) {
+ untreatedChildSet.add(childId);
+ LOGGER_DATA_MANAGER.debug(
+ "Could not update child ({}) because schema ({}) is different from the parent one ({}).",
+ new Object[]{childId, childSchema, parentSchema});
+ continue;
+ }
LOGGER_DATA_MANAGER.debug("Updating child ({}) ...", childId);
- // --- setup xml element to be processed by XSLT
-
- Element rootEl = new Element("root");
- Element childEl = new Element("child").addContent(child.detach());
- rootEl.addContent(childEl);
- rootEl.addContent(env.detach());
-
- // --- do an XSL transformation
-
- Path styleSheet = metadataSchemaUtils.getSchemaDir(parentSchema)
- .resolve(Geonet.File.UPDATE_CHILD_FROM_PARENT_INFO);
- Element childForUpdate = Xml.transform(rootEl, styleSheet, params);
-
- getXmlSerializer().update(childId, childForUpdate, new ISODate().toString(), true, null, srvContext);
-
- // Notifies the metadata change to metatada notifier service
- metadataUtils.notifyMetadataChange(childForUpdate, childId);
-
- rootEl = null;
- }
-
- return untreatedChildSet;
- }
-
- // ---------------------------------------------------------------------------
- // ---
- // --- Static methods are for external modules like GAST to be able to use
- // --- them.
- // ---
- // ---------------------------------------------------------------------------
-
- /**
- * Add privileges information about metadata record which depends on context and
- * usually could not be stored in db or Lucene index because depending on the
- * current user or current client IP address.
- *
- * @param mdIdToInfoMap
- * a map from the metadata Id -> the info element to which the
- * privilege information should be added.
- */
- @VisibleForTesting
- @Override
- public void buildPrivilegesMetadataInfo(ServiceContext context, Map mdIdToInfoMap)
- throws Exception {
- Collection metadataIds = Collections2.transform(mdIdToInfoMap.keySet(),
- new Function() {
- @Nullable
- @Override
- public Integer apply(String input) {
- return Integer.valueOf(input);
- }
- });
- Specification operationAllowedSpec = OperationAllowedSpecs.hasMetadataIdIn(metadataIds);
-
- final Collection allUserGroups = accessManager.getUserGroups(context.getUserSession(),
- context.getIpAddress(), false);
- final SetMultimap operationsPerMetadata = loadOperationsAllowed(context,
- where(operationAllowedSpec).and(OperationAllowedSpecs.hasGroupIdIn(allUserGroups)));
- final Set visibleToAll = loadOperationsAllowed(context,
- where(operationAllowedSpec).and(OperationAllowedSpecs.isPublic(ReservedOperation.view))).keySet();
- final Set downloadableByGuest = loadOperationsAllowed(context,
- where(operationAllowedSpec).and(OperationAllowedSpecs.hasGroupId(ReservedGroup.guest.getId()))
- .and(OperationAllowedSpecs.hasOperation(ReservedOperation.download))).keySet();
- final Map allSourceInfo = metadataRepository
- .findAllSourceInfo(MetadataSpecs.hasMetadataIdIn(metadataIds));
-
- for (Map.Entry entry : mdIdToInfoMap.entrySet()) {
- Element infoEl = entry.getValue();
- final Integer mdId = Integer.valueOf(entry.getKey());
- MetadataSourceInfo sourceInfo = allSourceInfo.get(mdId);
- Set operations = operationsPerMetadata.get(mdId);
- if (operations == null) {
- operations = Collections.emptySet();
- }
-
- boolean isOwner = accessManager.isOwner(context, sourceInfo);
-
- if (isOwner) {
- operations = Sets.newHashSet(Arrays.asList(ReservedOperation.values()));
- }
-
- if (isOwner || operations.contains(ReservedOperation.editing)) {
- addElement(infoEl, Edit.Info.Elem.EDIT, "true");
- }
-
- if (isOwner) {
- addElement(infoEl, Edit.Info.Elem.OWNER, "true");
- }
-
- addElement(infoEl, Edit.Info.Elem.IS_PUBLISHED_TO_ALL, visibleToAll.contains(mdId));
- addElement(infoEl, ReservedOperation.view.name(), operations.contains(ReservedOperation.view));
- addElement(infoEl, ReservedOperation.notify.name(), operations.contains(ReservedOperation.notify));
- addElement(infoEl, ReservedOperation.download.name(), operations.contains(ReservedOperation.download));
- addElement(infoEl, ReservedOperation.dynamic.name(), operations.contains(ReservedOperation.dynamic));
- addElement(infoEl, ReservedOperation.featured.name(), operations.contains(ReservedOperation.featured));
-
- if (!operations.contains(ReservedOperation.download)) {
- addElement(infoEl, Edit.Info.Elem.GUEST_DOWNLOAD, downloadableByGuest.contains(mdId));
- }
- }
- }
-
- private SetMultimap loadOperationsAllowed(ServiceContext context,
- Specification operationAllowedSpec) {
- final OperationAllowedRepository operationAllowedRepo = context.getBean(OperationAllowedRepository.class);
- List operationsAllowed = operationAllowedRepo.findAll(operationAllowedSpec);
- SetMultimap operationsPerMetadata = HashMultimap.create();
- for (OperationAllowed allowed : operationsAllowed) {
- final OperationAllowedId id = allowed.getId();
- operationsPerMetadata.put(id.getMetadataId(), ReservedOperation.lookup(id.getOperationId()));
- }
- return operationsPerMetadata;
- }
-
- /**
- *
- * @param md
- * @throws Exception
- */
- private void setNamespacePrefixUsingSchemas(String schema, Element md) throws Exception {
- // --- if the metadata has no namespace or already has a namespace prefix
- // --- then we must skip this phase
- Namespace ns = md.getNamespace();
- if (ns == Namespace.NO_NAMESPACE)
- return;
-
- MetadataSchema mds = schemaManager.getSchema(schema);
-
- // --- get the namespaces and add prefixes to any that are
- // --- default (ie. prefix is '') if namespace match one of the schema
- ArrayList nsList = new ArrayList();
- nsList.add(ns);
- @SuppressWarnings("unchecked")
- List additionalNamespaces = md.getAdditionalNamespaces();
- nsList.addAll(additionalNamespaces);
- for (Object aNsList : nsList) {
- Namespace aNs = (Namespace) aNsList;
- if (aNs.getPrefix().equals("")) { // found default namespace
- String prefix = mds.getPrefix(aNs.getURI());
- if (prefix == null) {
- LOGGER_DATA_MANAGER.warn("Metadata record contains a default namespace {} (with no prefix) which does not match any {} schema's namespaces.",
+ // --- setup xml element to be processed by XSLT
+
+ Element rootEl = new Element("root");
+ Element childEl = new Element("child").addContent(child.detach());
+ rootEl.addContent(childEl);
+ rootEl.addContent(env.detach());
+
+ // --- do an XSL transformation
+
+ Path styleSheet = metadataSchemaUtils.getSchemaDir(parentSchema)
+ .resolve(Geonet.File.UPDATE_CHILD_FROM_PARENT_INFO);
+ Element childForUpdate = Xml.transform(rootEl, styleSheet, params);
+
+ getXmlSerializer().update(childId, childForUpdate, new ISODate().toString(), true, null, srvContext);
+
+ // Notifies the metadata change to metatada notifier service
+ metadataUtils.notifyMetadataChange(childForUpdate, childId);
+
+ rootEl = null;
+ }
+
+ return untreatedChildSet;
+ }
+
+ // ---------------------------------------------------------------------------
+ // ---
+ // --- Static methods are for external modules like GAST to be able to use
+ // --- them.
+ // ---
+ // ---------------------------------------------------------------------------
+
+ /**
+ * Add privileges information about metadata record which depends on context and
+ * usually could not be stored in db or Lucene index because depending on the
+ * current user or current client IP address.
+ *
+ * @param mdIdToInfoMap a map from the metadata Id -> the info element to which the
+ * privilege information should be added.
+ */
+ @Override
+ public void buildPrivilegesMetadataInfo(ServiceContext context, Map mdIdToInfoMap)
+ throws Exception {
+ Collection metadataIds = Collections2.transform(mdIdToInfoMap.keySet(),
+ new Function() {
+ @Nullable
+ @Override
+ public Integer apply(String input) {
+ return Integer.valueOf(input);
+ }
+ });
+ Specification operationAllowedSpec = OperationAllowedSpecs.hasMetadataIdIn(metadataIds);
+
+ final Collection allUserGroups = accessManager.getUserGroups(context.getUserSession(),
+ context.getIpAddress(), false);
+ final SetMultimap operationsPerMetadata = loadOperationsAllowed(context,
+ where(operationAllowedSpec).and(OperationAllowedSpecs.hasGroupIdIn(allUserGroups)));
+ final Set visibleToAll = loadOperationsAllowed(context,
+ where(operationAllowedSpec).and(OperationAllowedSpecs.isPublic(ReservedOperation.view))).keySet();
+ final Set downloadableByGuest = loadOperationsAllowed(context,
+ where(operationAllowedSpec).and(OperationAllowedSpecs.hasGroupId(ReservedGroup.guest.getId()))
+ .and(OperationAllowedSpecs.hasOperation(ReservedOperation.download))).keySet();
+ final Map allSourceInfo = findAllSourceInfo((Specification) MetadataSpecs.hasMetadataIdIn(metadataIds));
+
+ for (Map.Entry entry : mdIdToInfoMap.entrySet()) {
+ Element infoEl = entry.getValue();
+ final Integer mdId = Integer.valueOf(entry.getKey());
+ MetadataSourceInfo sourceInfo = allSourceInfo.get(mdId);
+ Set operations = operationsPerMetadata.get(mdId);
+ if (operations == null) {
+ operations = Collections.emptySet();
+ }
+
+ boolean isOwner = accessManager.isOwner(context, sourceInfo);
+
+ if (isOwner) {
+ operations = Sets.newHashSet(Arrays.asList(ReservedOperation.values()));
+ }
+
+ if (isOwner || operations.contains(ReservedOperation.editing)) {
+ addElement(infoEl, Edit.Info.Elem.EDIT, "true");
+ }
+
+ if (isOwner) {
+ addElement(infoEl, Edit.Info.Elem.OWNER, "true");
+ }
+
+ addElement(infoEl, Edit.Info.Elem.IS_PUBLISHED_TO_ALL, visibleToAll.contains(mdId));
+ addElement(infoEl, ReservedOperation.view.name(), operations.contains(ReservedOperation.view));
+ addElement(infoEl, ReservedOperation.notify.name(), operations.contains(ReservedOperation.notify));
+ addElement(infoEl, ReservedOperation.download.name(), operations.contains(ReservedOperation.download));
+ addElement(infoEl, ReservedOperation.dynamic.name(), operations.contains(ReservedOperation.dynamic));
+ addElement(infoEl, ReservedOperation.featured.name(), operations.contains(ReservedOperation.featured));
+
+ if (!operations.contains(ReservedOperation.download)) {
+ addElement(infoEl, Edit.Info.Elem.GUEST_DOWNLOAD, downloadableByGuest.contains(mdId));
+ }
+ }
+ }
+
+ protected SetMultimap loadOperationsAllowed(ServiceContext context,
+ Specification operationAllowedSpec) {
+ final OperationAllowedRepository operationAllowedRepo = context.getBean(OperationAllowedRepository.class);
+ List operationsAllowed = operationAllowedRepo.findAll(operationAllowedSpec);
+ SetMultimap operationsPerMetadata = HashMultimap.create();
+ for (OperationAllowed allowed : operationsAllowed) {
+ final OperationAllowedId id = allowed.getId();
+ operationsPerMetadata.put(id.getMetadataId(), ReservedOperation.lookup(id.getOperationId()));
+ }
+ return operationsPerMetadata;
+ }
+
+ /**
+ * @param md
+ * @throws Exception
+ */
+ private void setNamespacePrefixUsingSchemas(String schema, Element md) throws Exception {
+ // --- if the metadata has no namespace or already has a namespace prefix
+ // --- then we must skip this phase
+ Namespace ns = md.getNamespace();
+ if (ns == Namespace.NO_NAMESPACE)
+ return;
+
+ MetadataSchema mds = schemaManager.getSchema(schema);
+
+ // --- get the namespaces and add prefixes to any that are
+ // --- default (ie. prefix is '') if namespace match one of the schema
+ ArrayList nsList = new ArrayList();
+ nsList.add(ns);
+ @SuppressWarnings("unchecked")
+ List additionalNamespaces = md.getAdditionalNamespaces();
+ nsList.addAll(additionalNamespaces);
+ for (Object aNsList : nsList) {
+ Namespace aNs = (Namespace) aNsList;
+ if (aNs.getPrefix().equals("")) { // found default namespace
+ String prefix = mds.getPrefix(aNs.getURI());
+ if (prefix == null) {
+ LOGGER_DATA_MANAGER.warn(
+ "Metadata record contains a default namespace {} (with no prefix) which does not match any {} schema's namespaces.",
aNs.getURI(), schema);
- }
- ns = Namespace.getNamespace(prefix, aNs.getURI());
- metadataValidator.setNamespacePrefix(md, ns);
- if (!md.getNamespace().equals(ns)) {
- md.removeNamespaceDeclaration(aNs);
- md.addNamespaceDeclaration(ns);
- }
- }
- }
- }
-
- /**
- *
- * @param root
- * @param name
- * @param value
- */
- private static void addElement(Element root, String name, Object value) {
- root.addContent(new Element(name).setText(value == null ? "" : value.toString()));
- }
-
- @Override
- public AbstractMetadata save(AbstractMetadata info) {
- if (info instanceof Metadata) {
- return metadataRepository.save((Metadata) info);
- } else {
- throw new NotImplementedException("Unknown IMetadata subtype: " + info.getClass().getName());
- }
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public AbstractMetadata update(int id, @Nonnull Updater extends AbstractMetadata> updater) {
- return metadataRepository.update(id, (Updater) updater);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public void deleteAll(Specification extends AbstractMetadata> specs) {
- try {
- metadataRepository.deleteAll((Specification) specs);
- } catch (Throwable t) {
- t.printStackTrace();
- // Maybe it is not a Specification
- }
- }
-
- @Override
- public void delete(Integer id) {
- metadataRepository.delete(id);
- }
-
- @Override
- public void createBatchUpdateQuery(PathSpec servicesPath, String newUuid,
- Specification harvested) {
- metadataRepository.createBatchUpdateQuery(servicesPath, newUuid, harvested);
- }
+ }
+ ns = Namespace.getNamespace(prefix, aNs.getURI());
+ metadataValidator.setNamespacePrefix(md, ns);
+ if (!md.getNamespace().equals(ns)) {
+ md.removeNamespaceDeclaration(aNs);
+ md.addNamespaceDeclaration(ns);
+ }
+ }
+ }
+ }
+
+ /**
+ * @param root
+ * @param name
+ * @param value
+ */
+ protected static void addElement(Element root, String name, Object value) {
+ root.addContent(new Element(name).setText(value == null ? "" : value.toString()));
+ }
+
+ @Override
+ public AbstractMetadata save(AbstractMetadata info) {
+ if (info instanceof Metadata) {
+ return metadataRepository.save((Metadata) info);
+ } else {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + info.getClass().getName());
+ }
+ }
+
+ @Override
+ public AbstractMetadata update(int id, @Nonnull Updater extends AbstractMetadata> updater) {
+ try {
+ return metadataRepository.update(id, (Updater) updater);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + updater.getClass().getName());
+ }
+ }
+
+ @Override
+ public void deleteAll(Specification extends AbstractMetadata> specs) {
+ try {
+ metadataRepository.deleteAll((Specification) specs);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + specs.getClass().getName());
+ }
+ }
+
+ @Override
+ @Transactional
+ public void delete(Integer id) {
+ Log.trace(Geonet.DATA_MANAGER, "Deleting record with id " + id);
+ if (metadataRepository.exists(id)) {
+ metadataRepository.delete(id);
+ }
+ }
+
+ @Override
+ public void createBatchUpdateQuery(PathSpec extends AbstractMetadata, String> servicesPath, String newUuid,
+ Specification extends AbstractMetadata> harvested) {
+ try {
+ metadataRepository.createBatchUpdateQuery((PathSpec) servicesPath, newUuid,
+ (Specification) harvested);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + servicesPath.getClass().getName());
+ }
+ }
+
+
+ @Override
+ public Map findAllSourceInfo(Specification extends AbstractMetadata> specs) {
+ try {
+ return metadataRepository.findAllSourceInfo((Specification) specs);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + specs.getClass().getName());
+ }
+ }
}
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java
index 0ee92f546dd..a35d2063f87 100644
--- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataOperations.java
@@ -1,7 +1,31 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
package org.fao.geonet.kernel.datamanager.base;
import static org.springframework.data.jpa.domain.Specifications.where;
+import java.util.Collection;
import java.util.List;
import org.apache.commons.lang.StringUtils;
@@ -14,6 +38,8 @@
import org.fao.geonet.domain.ReservedOperation;
import org.fao.geonet.domain.UserGroup;
import org.fao.geonet.domain.UserGroupId;
+import org.fao.geonet.events.md.MetadataPublished;
+import org.fao.geonet.events.md.MetadataUnpublished;
import org.fao.geonet.exceptions.ServiceNotAllowedEx;
import org.fao.geonet.kernel.SvnManager;
import org.fao.geonet.kernel.datamanager.IMetadataOperations;
@@ -28,6 +54,8 @@
import org.fao.geonet.repository.specification.UserSpecs;
import org.fao.geonet.utils.Log;
import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationEventPublisher;
+import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.jpa.domain.Specification;
@@ -35,7 +63,7 @@
import jeeves.server.context.ServiceContext;
-public class BaseMetadataOperations implements IMetadataOperations {
+public class BaseMetadataOperations implements IMetadataOperations, ApplicationEventPublisherAware {
@Autowired
private IMetadataUtils metadataUtils;
@@ -48,9 +76,21 @@ public class BaseMetadataOperations implements IMetadataOperations {
@Autowired
@Lazy
private SettingManager settingManager;
- @Autowired(required=false)
+ @Autowired(required = false)
private SvnManager svnManager;
+ private ApplicationEventPublisher eventPublisher;
+
+ /**
+ * @see org.springframework.context.ApplicationEventPublisherAware#setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher)
+ */
+ @Override
+ public void setApplicationEventPublisher(
+ ApplicationEventPublisher applicationEventPublisher) {
+ this.eventPublisher = applicationEventPublisher;
+ }
+
+
public void init(ServiceContext context, Boolean force) throws Exception {
userRepository = context.getBean(UserRepository.class);
metadataUtils = context.getBean(IMetadataUtils.class);
@@ -65,13 +105,19 @@ public void init(ServiceContext context, Boolean force) throws Exception {
*/
@Override
public void deleteMetadataOper(ServiceContext context, String metadataId, boolean skipAllReservedGroup) throws Exception {
- OperationAllowedRepository operationAllowedRepository = context.getBean(OperationAllowedRepository.class);
+ deleteMetadataOper(metadataId, skipAllReservedGroup);
+ }
+ /**
+ * Removes all operations stored for a metadata.
+ */
+ @Override
+ public void deleteMetadataOper(String metadataId, boolean skipAllReservedGroup) throws Exception {
if (skipAllReservedGroup) {
- int[] exclude = new int[] { ReservedGroup.all.getId(), ReservedGroup.intranet.getId(), ReservedGroup.guest.getId() };
- operationAllowedRepository.deleteAllByMetadataIdExceptGroupId(Integer.parseInt(metadataId), exclude);
+ int[] exclude = new int[]{ReservedGroup.all.getId(), ReservedGroup.intranet.getId(), ReservedGroup.guest.getId()};
+ opAllowedRepo.deleteAllByMetadataIdExceptGroupId(Integer.parseInt(metadataId), exclude);
} else {
- operationAllowedRepository.deleteAllByIdAttribute(OperationAllowedId_.metadataId, Integer.parseInt(metadataId));
+ opAllowedRepo.deleteAllByMetadataId(Integer.parseInt(metadataId));
}
}
@@ -93,15 +139,15 @@ public void setOperation(ServiceContext context, String mdId, String grpId, Stri
/**
* Set metadata privileges.
- *
+ *
* Administrator can set operation for any groups.
- *
+ *
* For reserved group (ie. Internet, Intranet & Guest), user MUST be reviewer of one group. For other group, if "Only set privileges to
* user's groups" is set in catalog configuration user MUST be a member of the group.
*
- * @param mdId The metadata identifier
+ * @param mdId The metadata identifier
* @param grpId The group identifier
- * @param opId The operation identifier
+ * @param opId The operation identifier
* @return true if the operation was set.
*/
@Override
@@ -110,8 +156,37 @@ public boolean setOperation(ServiceContext context, int mdId, int grpId, int opI
// Set operation
if (opAllowed.isPresent()) {
+ return forceSetOperation(context, mdId, grpId, opId);
+ }
+
+ return false;
+ }
+
+ /**
+ * Set metadata privileges.
+ *
+ * @param mdId The metadata identifier
+ * @param grpId The group identifier
+ * @param opId The operation identifier
+ * @return true if the operation was set.
+ */
+ @Override
+ public boolean forceSetOperation(ServiceContext context, int mdId, int grpId, int opId) throws Exception {
+ Optional opAllowed = _getOperationAllowedToAdd(context, mdId, grpId, opId, false);
+
+ if (opAllowed.isPresent()) {
+ Log.trace(Geonet.DATA_MANAGER, "Operation is allowed");
opAllowedRepo.save(opAllowed.get());
svnManager.setHistory(mdId + "", context);
+
+ //If it is published/unpublished, throw event
+ if (opId == ReservedOperation.view.getId()
+ && grpId == ReservedGroup.all.getId()) {
+ Log.trace(Geonet.DATA_MANAGER, "This is a publish event");
+ this.eventPublisher.publishEvent(new MetadataPublished(
+ metadataUtils.findOne(Integer.valueOf(mdId))));
+ }
+
return true;
}
@@ -128,16 +203,26 @@ public boolean setOperation(ServiceContext context, int mdId, int grpId, int opI
*/
@Override
public Optional getOperationAllowedToAdd(final ServiceContext context, final int mdId, final int grpId,
- final int opId) {
+ final int opId) {
+ return _getOperationAllowedToAdd(context, mdId, grpId, opId, true);
+ }
+
+ private Optional _getOperationAllowedToAdd(final ServiceContext context, final int mdId, final int grpId,
+ final int opId, boolean shouldCheckPermission) {
+ Log.trace(Geonet.DATA_MANAGER, "_getOperationAllowedToAdd(" + mdId + ", "
+ + grpId + ", " + opId + ", " + shouldCheckPermission + ")");
final OperationAllowed operationAllowed = opAllowedRepo.findOneById_GroupIdAndId_MetadataIdAndId_OperationId(grpId, mdId, opId);
- if (operationAllowed == null) {
+ if (operationAllowed == null && shouldCheckPermission) {
+ Log.trace(Geonet.DATA_MANAGER, "Checking if the operation is allowed, the operation is not yet present");
checkOperationPermission(context, grpId, userGroupRepo);
}
if (operationAllowed == null) {
+ Log.trace(Geonet.DATA_MANAGER, "Returning operation to add");
return Optional.of(new OperationAllowed(new OperationAllowedId().setGroupId(grpId).setMetadataId(mdId).setOperationId(opId)));
} else {
+ Log.trace(Geonet.DATA_MANAGER, "Operation is already available");
return Optional.absent();
}
}
@@ -154,12 +239,12 @@ public void checkOperationPermission(ServiceContext context, int grpId, UserGrou
if (ReservedGroup.isReserved(grpId)) {
Specification hasUserIdAndProfile = where(UserGroupSpecs.hasProfile(Profile.Reviewer))
- .and(UserGroupSpecs.hasUserId(userId));
+ .and(UserGroupSpecs.hasUserId(userId));
List groupIds = userGroupRepo.findGroupIds(hasUserIdAndProfile);
if (groupIds.isEmpty()) {
throw new ServiceNotAllowedEx(
- "User can't set operation for group " + grpId + " because the user in not a " + "Reviewer of any group.");
+ "User can't set operation for group " + grpId + " because the user in not a " + "Reviewer of any group.");
}
} else {
String userGroupsOnly = settingManager.getValue(Settings.SYSTEM_METADATAPRIVS_USERGROUPONLY);
@@ -168,7 +253,7 @@ public void checkOperationPermission(ServiceContext context, int grpId, UserGrou
if (userGroupRepo.exists(new UserGroupId().setGroupId(grpId).setUserId(userId))) {
throw new ServiceNotAllowedEx(
- "User can't set operation for group " + grpId + " because the user in not" + " member of this group.");
+ "User can't set operation for group " + grpId + " because the user in not" + " member of this group.");
}
}
}
@@ -177,7 +262,6 @@ public void checkOperationPermission(ServiceContext context, int grpId, UserGrou
}
/**
- *
* @param context
* @param mdId
* @param grpId
@@ -190,7 +274,6 @@ public void unsetOperation(ServiceContext context, String mdId, String grpId, Re
}
/**
- *
* @param context
* @param mdId
* @param grpId
@@ -209,9 +292,9 @@ public void unsetOperation(ServiceContext context, String mdId, String grpId, St
// --------------------------------------------------------------------------
/**
- * @param mdId metadata id
+ * @param mdId metadata id
* @param groupId group id
- * @param operId operation id
+ * @param operId operation id
*/
@Override
public void unsetOperation(ServiceContext context, int mdId, int groupId, int operId) throws Exception {
@@ -226,22 +309,30 @@ public void unsetOperation(ServiceContext context, int mdId, int groupId, int op
@Override
public void forceUnsetOperation(ServiceContext context, int mdId, int groupId, int operId) throws Exception {
OperationAllowedId id = new OperationAllowedId().setGroupId(groupId).setMetadataId(mdId).setOperationId(operId);
- final OperationAllowedRepository repository = context.getBean(OperationAllowedRepository.class);
- if (repository.exists(id)) {
- repository.delete(id);
+ if (opAllowedRepo.exists(id)) {
+ opAllowedRepo.delete(id);
if (svnManager != null) {
svnManager.setHistory(mdId + "", context);
}
+
+ //If it is published/unpublished, throw event
+ if (operId == ReservedOperation.view.getId()
+ && groupId == ReservedGroup.all.getId()) {
+
+ this.eventPublisher.publishEvent(new MetadataUnpublished(
+ metadataUtils.findOne(Integer.valueOf(mdId))));
+ }
+
}
}
/**
* Sets VIEW and NOTIFY privileges for a metadata to a group.
*
- * @param context service context
- * @param id metadata id
- * @param groupId group id
- * @param fullRightsForGroup
+ * @param context service context
+ * @param id metadata id
+ * @param groupId group id
+ * @param fullRightsForGroup
* @throws Exception hmmm
*/
@Override
@@ -275,4 +366,9 @@ public boolean isUserMetadataOwner(int userId) throws Exception {
public boolean existsUser(ServiceContext context, int id) throws Exception {
return userRepository.count(where(UserSpecs.hasUserId(id))) > 0;
}
+
+ @Override
+ public Collection getAllOperations(int id) {
+ return opAllowedRepo.findAllById_MetadataId(id);
+ }
}
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataSchemaUtils.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataSchemaUtils.java
index 49e51406625..5243891b5df 100644
--- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataSchemaUtils.java
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataSchemaUtils.java
@@ -1,3 +1,26 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
package org.fao.geonet.kernel.datamanager.base;
import java.nio.file.Path;
@@ -33,7 +56,6 @@ public void init(ServiceContext context, Boolean force) throws Exception {
}
/**
- *
* @param name
* @return
*/
@@ -43,7 +65,6 @@ public MetadataSchema getSchema(String name) {
}
/**
- *
* @return
*/
@Override
@@ -52,7 +73,6 @@ public Set getSchemas() {
}
/**
- *
* @param name
* @return
*/
@@ -62,7 +82,6 @@ public boolean existsSchema(String name) {
}
/**
- *
* @param name
* @return
*/
@@ -93,7 +112,8 @@ public String getMetadataSchema(String id) throws Exception {
* @param md Record to checked against schemas
*/
@Override
- public @CheckForNull String autodetectSchema(Element md) throws SchemaMatchConflictException, NoSchemaMatchesException {
+ public @CheckForNull
+ String autodetectSchema(Element md) throws SchemaMatchConflictException, NoSchemaMatchesException {
return autodetectSchema(md, schemaManager.getDefaultSchema());
}
@@ -101,17 +121,18 @@ public String getMetadataSchema(String id) throws Exception {
* Checks autodetect elements in installed schemas to determine whether the metadata record belongs to that schema. Use this method when
* you want to set the default schema to be returned when no other match can be found.
*
- * @param md Record to checked against schemas
+ * @param md Record to checked against schemas
* @param defaultSchema Schema to be assigned when no other schema matches
*/
@Override
- public @CheckForNull String autodetectSchema(Element md, String defaultSchema)
- throws SchemaMatchConflictException, NoSchemaMatchesException {
+ public @CheckForNull
+ String autodetectSchema(Element md, String defaultSchema)
+ throws SchemaMatchConflictException, NoSchemaMatchesException {
if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
Log.debug(Geonet.DATA_MANAGER,
- "Autodetect schema for metadata with :\n * root element:'" + md.getQualifiedName() + "'\n * with namespace:'"
- + md.getNamespace() + "\n * with additional namespaces:" + md.getAdditionalNamespaces().toString());
+ "Autodetect schema for metadata with :\n * root element:'" + md.getQualifiedName() + "'\n * with namespace:'"
+ + md.getNamespace() + "\n * with additional namespaces:" + md.getAdditionalNamespaces().toString());
String schema = schemaManager.autodetectSchema(md, defaultSchema);
if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
Log.debug(Geonet.DATA_MANAGER, "Schema detected was " + schema);
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java
index 5c6b4346670..9dbf8edd4a8 100644
--- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataStatus.java
@@ -1,3 +1,26 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
package org.fao.geonet.kernel.datamanager.base;
import java.util.List;
@@ -115,6 +138,7 @@ public MetadataStatus setStatus(ServiceContext context, int id, int status, ISOD
metadataIndexer.indexMetadata(Integer.toString(id), true, null);
return statusObject;
}
+
@Override
public MetadataStatus setStatusExt(MetadataStatus metatatStatus) throws Exception {
metadataStatusRepository.save(metatatStatus);
@@ -129,14 +153,14 @@ public MetadataStatus setStatusExt(MetadataStatus metatatStatus) throws Exceptio
*/
@Override
public MetadataStatus setStatusExt(ServiceContext context, int id, int status, ISODate changeDate, String changeMessage)
- throws Exception {
+ throws Exception {
MetadataStatus metatatStatus = new MetadataStatus();
metatatStatus.setChangeMessage(changeMessage);
metatatStatus.setStatusValue(statusValueRepository.findOne(status));
int userId = context.getUserSession().getUserIdAsInt();
MetadataStatusId mdStatusId = new MetadataStatusId().setStatusId(status).setMetadataId(id).setChangeDate(changeDate)
- .setUserId(userId);
+ .setUserId(userId);
mdStatusId.setChangeDate(changeDate);
metatatStatus.setId(mdStatusId);
@@ -165,8 +189,8 @@ public void activateWorkflowIfConfigured(ServiceContext context, String newId, S
final Matcher matcher = pattern.matcher(groupName);
if (matcher.find()) {
setStatus(context, Integer.valueOf(newId), Integer.valueOf(StatusValue.Status.DRAFT), new ISODate(),
- String.format("Workflow automatically enabled for record in group %s. Record status is set to %s.", groupName,
- StatusValue.Status.DRAFT));
+ String.format("Workflow automatically enabled for record in group %s. Record status is set to %s.", groupName,
+ StatusValue.Status.DRAFT));
}
}
}
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java
index cbcde07371c..355bf37f76e 100644
--- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataUtils.java
@@ -1,30 +1,53 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
package org.fao.geonet.kernel.datamanager.base;
import static org.fao.geonet.repository.specification.MetadataSpecs.hasMetadataUuid;
import java.nio.file.Path;
import java.util.ArrayList;
+import java.util.Collections;
import java.util.List;
+import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.PostConstruct;
-import javax.persistence.criteria.CriteriaBuilder;
-import javax.persistence.criteria.CriteriaQuery;
-import javax.persistence.criteria.Predicate;
-import javax.persistence.criteria.Root;
import org.apache.commons.lang.NotImplementedException;
import org.fao.geonet.NodeInfo;
import org.fao.geonet.constants.Edit;
import org.fao.geonet.constants.Geonet;
import org.fao.geonet.domain.AbstractMetadata;
+import org.fao.geonet.domain.ISODate;
import org.fao.geonet.domain.Metadata;
import org.fao.geonet.domain.MetadataDataInfo;
import org.fao.geonet.domain.MetadataHarvestInfo;
import org.fao.geonet.domain.MetadataRatingByIp;
import org.fao.geonet.domain.MetadataRatingByIpId;
+import org.fao.geonet.domain.MetadataSourceInfo;
import org.fao.geonet.domain.MetadataType;
import org.fao.geonet.domain.Pair;
import org.fao.geonet.domain.ReservedOperation;
@@ -52,6 +75,8 @@
import org.jdom.Namespace;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
+import org.springframework.dao.IncorrectResultSizeDataAccessException;
+import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
@@ -62,207 +87,206 @@
import jeeves.server.context.ServiceContext;
public class BaseMetadataUtils implements IMetadataUtils {
- @Autowired
- private MetadataRepository metadataRepository;
-
- @Autowired
- private MetadataNotifierManager metadataNotifierManager;
-
- // FIXME Remove when get rid of Jeeves
- private ServiceContext servContext;
- @Autowired
- private IMetadataSchemaUtils metadataSchemaUtils;
- @Autowired
- private IMetadataIndexer metadataIndexer;
- @Autowired
- private SchemaManager schemaManager;
- @Autowired
- protected MetadataRatingByIpRepository ratingByIpRepository;
- @Autowired
- @Lazy
- private SettingManager settingManager;
-
- @Autowired
- private IndexingList indexingList;
-
- @Autowired(required = false)
- private XmlSerializer xmlSerializer;
-
- private Path stylePath;
-
- private IMetadataManager metadataManager;
-
- @Override
- public void setMetadataManager(IMetadataManager metadataManager) {
- this.metadataManager = metadataManager;
- }
-
- @SuppressWarnings("unchecked")
- public void init(ServiceContext context, Boolean force) throws Exception {
- metadataRepository = context.getBean(MetadataRepository.class);
- metadataNotifierManager = context.getBean(MetadataNotifierManager.class);
- servContext = context;
- schemaManager = context.getBean(SchemaManager.class);
- metadataSchemaUtils = context.getBean(IMetadataSchemaUtils.class);
- metadataIndexer = context.getBean(IMetadataIndexer.class);
- ratingByIpRepository = context.getBean(MetadataRatingByIpRepository.class);
- settingManager = context.getBean(SettingManager.class);
- xmlSerializer = context.getBean(XmlSerializer.class);
- indexingList = context.getBean(IndexingList.class);
-
- final GeonetworkDataDirectory dataDirectory = context.getBean(GeonetworkDataDirectory.class);
- stylePath = dataDirectory.resolveWebResource(Geonet.Path.STYLESHEETS);
- }
-
- /**
- * Needed to avoid circular dependency injection
- */
- @PostConstruct
- public void init() {
- this.metadataIndexer.setMetadataUtils(this);
- }
-
- /**
- *
- * @param md
- * @param metadataId
- * @throws Exception
- */
- @Override
- public void notifyMetadataChange(Element md, String metadataId) throws Exception {
- final AbstractMetadata metadata = findOne(metadataId);
- if (metadata != null && metadata.getDataInfo().getType() == MetadataType.METADATA) {
- MetadataSchema mds = schemaManager.getSchema(metadata.getDataInfo().getSchemaId());
- Pair editXpathFilter = mds.getOperationFilter(ReservedOperation.editing);
- XmlSerializer.removeFilteredElement(md, editXpathFilter, mds.getNamespaces());
-
- String uuid = getMetadataUuid(metadataId);
- metadataNotifierManager.updateMetadata(md, metadataId, uuid, getServiceContext());
- }
- }
-
- /**
- *
- * @param id
- * @return
- * @throws Exception
- */
- public @Nullable @Override String getMetadataUuid(@Nonnull String id) throws Exception {
- AbstractMetadata metadata = findOne(id);
-
- if (metadata == null)
- return null;
-
- return metadata.getUuid();
- }
-
- protected ServiceContext getServiceContext() {
- ServiceContext context = ServiceContext.get();
- return context == null ? servContext : context;
- }
-
- /**
- * Start an editing session. This will record the original metadata record in
- * the session under the
- * {@link org.fao.geonet.constants.Geonet.Session#METADATA_BEFORE_ANY_CHANGES} +
- * id session property.
- *
- * The record contains geonet:info element.
- *
- * Note: Only the metadata record is stored in session. If the editing session
- * upload new documents or thumbnails, those documents will not be cancelled.
- * This needs improvements.
- */
- @Override
- public void startEditingSession(ServiceContext context, String id) throws Exception {
- if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
- Log.debug(Geonet.EDITOR_SESSION, "Editing session starts for record " + id);
- }
-
- boolean keepXlinkAttributes = true;
- boolean forEditing = false;
- boolean withValidationErrors = false;
- Element metadataBeforeAnyChanges = context.getBean(IMetadataManager.class).getMetadata(context, id, forEditing,
- withValidationErrors, keepXlinkAttributes);
- context.getUserSession().setProperty(Geonet.Session.METADATA_BEFORE_ANY_CHANGES + id, metadataBeforeAnyChanges);
- }
-
- /**
- * Rollback to the record in the state it was when the editing session started
- * (See {@link #startEditingSession(ServiceContext, String)}).
- */
- @Override
- public void cancelEditingSession(ServiceContext context, String id) throws Exception {
- UserSession session = context.getUserSession();
- Element metadataBeforeAnyChanges = (Element) session
- .getProperty(Geonet.Session.METADATA_BEFORE_ANY_CHANGES + id);
-
- if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
- Log.debug(Geonet.EDITOR_SESSION, "Editing session end. Cancel changes. Restore record " + id
- + ". Replace by original record which was: ");
- }
-
- if (metadataBeforeAnyChanges != null) {
- if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
- Log.debug(Geonet.EDITOR_SESSION, " > restoring record: ");
- Log.debug(Geonet.EDITOR_SESSION, Xml.getString(metadataBeforeAnyChanges));
- }
- Element info = metadataBeforeAnyChanges.getChild(Edit.RootChild.INFO, Edit.NAMESPACE);
- boolean validate = false;
- boolean ufo = false;
- boolean index = true;
- metadataBeforeAnyChanges.removeChild(Edit.RootChild.INFO, Edit.NAMESPACE);
- context.getBean(IMetadataManager.class).updateMetadata(context, id, metadataBeforeAnyChanges, validate, ufo,
- index, context.getLanguage(), info.getChildText(Edit.Info.Elem.CHANGE_DATE), false);
- endEditingSession(id, session);
- } else {
- if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
- Log.debug(Geonet.EDITOR_SESSION, " > nothing to cancel for record " + id
- + ". Original record was null. Use starteditingsession to.");
- }
- }
- }
-
- /**
- * Remove the original record stored in session.
- */
- @Override
- public void endEditingSession(String id, UserSession session) {
- if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
- Log.debug(Geonet.EDITOR_SESSION, "Editing session end.");
- }
- session.removeProperty(Geonet.Session.METADATA_BEFORE_ANY_CHANGES + id);
- }
-
- /**
- *
- * @param md
- * @return
- * @throws Exception
- */
- @Override
- public Element enumerateTree(Element md) throws Exception {
- metadataManager.getEditLib().enumerateTree(md);
- return md;
- }
-
- /**
- * Extract UUID from the metadata record using the schema XSL for UUID
- * extraction)
- */
- @Override
- public String extractUUID(String schema, Element md) throws Exception {
- Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_UUID);
- String uuid = Xml.transform(md, styleSheet).getText().trim();
-
- if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
- Log.debug(Geonet.DATA_MANAGER, "Extracted UUID '" + uuid + "' for schema '" + schema + "'");
-
- // --- needed to detach md from the document
- md.detach();
-
- return uuid;
- }
+ @Autowired
+ private MetadataRepository metadataRepository;
+
+ @Autowired
+ private MetadataNotifierManager metadataNotifierManager;
+
+ // FIXME Remove when get rid of Jeeves
+ private ServiceContext servContext;
+ @Autowired
+ protected IMetadataSchemaUtils metadataSchemaUtils;
+ @Autowired
+ protected IMetadataIndexer metadataIndexer;
+ @Autowired
+ protected SchemaManager schemaManager;
+ @Autowired
+ protected MetadataRatingByIpRepository ratingByIpRepository;
+ @Autowired
+ @Lazy
+ protected SettingManager settingManager;
+
+ @Autowired
+ private IndexingList indexingList;
+
+ @Autowired(required = false)
+ protected XmlSerializer xmlSerializer;
+
+ private Path stylePath;
+
+ protected IMetadataManager metadataManager;
+
+ @Override
+ public void setMetadataManager(IMetadataManager metadataManager) {
+ this.metadataManager = metadataManager;
+ }
+
+ public void init(ServiceContext context, Boolean force) throws Exception {
+ metadataRepository = context.getBean(MetadataRepository.class);
+ metadataNotifierManager = context.getBean(MetadataNotifierManager.class);
+ servContext = context;
+ schemaManager = context.getBean(SchemaManager.class);
+ metadataSchemaUtils = context.getBean(IMetadataSchemaUtils.class);
+ metadataIndexer = context.getBean(IMetadataIndexer.class);
+ ratingByIpRepository = context.getBean(MetadataRatingByIpRepository.class);
+ settingManager = context.getBean(SettingManager.class);
+ xmlSerializer = context.getBean(XmlSerializer.class);
+ indexingList = context.getBean(IndexingList.class);
+
+ final GeonetworkDataDirectory dataDirectory = context.getBean(GeonetworkDataDirectory.class);
+ stylePath = dataDirectory.resolveWebResource(Geonet.Path.STYLESHEETS);
+ }
+
+ /**
+ * Needed to avoid circular dependency injection
+ */
+ @PostConstruct
+ public void init() {
+ this.metadataIndexer.setMetadataUtils(this);
+ }
+
+ /**
+ * @param md
+ * @param metadataId
+ * @throws Exception
+ */
+ @Override
+ public void notifyMetadataChange(Element md, String metadataId) throws Exception {
+ final AbstractMetadata metadata = findOne(metadataId);
+ if (metadata != null && metadata.getDataInfo().getType() == MetadataType.METADATA) {
+ MetadataSchema mds = schemaManager.getSchema(metadata.getDataInfo().getSchemaId());
+ Pair editXpathFilter = mds.getOperationFilter(ReservedOperation.editing);
+ XmlSerializer.removeFilteredElement(md, editXpathFilter, mds.getNamespaces());
+
+ String uuid = getMetadataUuid(metadataId);
+ metadataNotifierManager.updateMetadata(md, metadataId, uuid, getServiceContext());
+ }
+ }
+
+ /**
+ * @param id
+ * @return
+ * @throws Exception
+ */
+ public @Nullable
+ @Override
+ String getMetadataUuid(@Nonnull String id) throws Exception {
+ AbstractMetadata metadata = findOne(id);
+
+ if (metadata == null)
+ return null;
+
+ return metadata.getUuid();
+ }
+
+ protected ServiceContext getServiceContext() {
+ ServiceContext context = ServiceContext.get();
+ return context == null ? servContext : context;
+ }
+
+ /**
+ * Start an editing session. This will record the original metadata record in
+ * the session under the
+ * {@link org.fao.geonet.constants.Geonet.Session#METADATA_BEFORE_ANY_CHANGES} +
+ * id session property.
+ *
+ * The record contains geonet:info element.
+ *
+ * Note: Only the metadata record is stored in session. If the editing session
+ * upload new documents or thumbnails, those documents will not be cancelled.
+ * This needs improvements.
+ */
+ @Override
+ public Integer startEditingSession(ServiceContext context, String id) throws Exception {
+ if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
+ Log.debug(Geonet.EDITOR_SESSION, "Editing session starts for record " + id);
+ }
+
+ boolean keepXlinkAttributes = true;
+ boolean forEditing = false;
+ boolean withValidationErrors = false;
+ Element metadataBeforeAnyChanges = context.getBean(IMetadataManager.class).getMetadata(context, id, forEditing,
+ withValidationErrors, keepXlinkAttributes);
+ context.getUserSession().setProperty(Geonet.Session.METADATA_BEFORE_ANY_CHANGES + id, metadataBeforeAnyChanges);
+ return Integer.valueOf(id);
+ }
+
+ /**
+ * Rollback to the record in the state it was when the editing session started
+ * (See {@link #startEditingSession(ServiceContext, String)}).
+ */
+ @Override
+ public void cancelEditingSession(ServiceContext context, String id) throws Exception {
+ UserSession session = context.getUserSession();
+ Element metadataBeforeAnyChanges = (Element) session
+ .getProperty(Geonet.Session.METADATA_BEFORE_ANY_CHANGES + id);
+
+ if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
+ Log.debug(Geonet.EDITOR_SESSION, "Editing session end. Cancel changes. Restore record " + id
+ + ". Replace by original record which was: ");
+ }
+
+ if (metadataBeforeAnyChanges != null) {
+ if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
+ Log.debug(Geonet.EDITOR_SESSION, " > restoring record: ");
+ Log.debug(Geonet.EDITOR_SESSION, Xml.getString(metadataBeforeAnyChanges));
+ }
+ Element info = metadataBeforeAnyChanges.getChild(Edit.RootChild.INFO, Edit.NAMESPACE);
+ boolean validate = false;
+ boolean ufo = false;
+ boolean index = true;
+ metadataBeforeAnyChanges.removeChild(Edit.RootChild.INFO, Edit.NAMESPACE);
+ context.getBean(IMetadataManager.class).updateMetadata(context, id, metadataBeforeAnyChanges, validate, ufo,
+ index, context.getLanguage(), info.getChildText(Edit.Info.Elem.CHANGE_DATE), false);
+ endEditingSession(id, session);
+ } else {
+ if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
+ Log.debug(Geonet.EDITOR_SESSION, " > nothing to cancel for record " + id
+ + ". Original record was null. Use starteditingsession to.");
+ }
+ }
+ }
+
+ /**
+ * Remove the original record stored in session.
+ */
+ @Override
+ public void endEditingSession(String id, UserSession session) {
+ if (Log.isDebugEnabled(Geonet.EDITOR_SESSION)) {
+ Log.debug(Geonet.EDITOR_SESSION, "Editing session end.");
+ }
+ session.removeProperty(Geonet.Session.METADATA_BEFORE_ANY_CHANGES + id);
+ }
+
+ /**
+ * @param md
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public Element enumerateTree(Element md) throws Exception {
+ metadataManager.getEditLib().enumerateTree(md);
+ return md;
+ }
+
+ /**
+ * Extract UUID from the metadata record using the schema XSL for UUID
+ * extraction)
+ */
+ @Override
+ public String extractUUID(String schema, Element md) throws Exception {
+ Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_UUID);
+ String uuid = Xml.transform(md, styleSheet).getText().trim();
+
+ if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
+ Log.debug(Geonet.DATA_MANAGER, "Extracted UUID '" + uuid + "' for schema '" + schema + "'");
+
+ // --- needed to detach md from the document
+ md.detach();
+
+ return uuid;
+ }
/**
* Extract metadata default language from the metadata record using the schema XSL for default language extraction)
@@ -283,680 +307,693 @@ public String extractDefaultLanguage(String schema, Element md) throws Exception
/**
- *
- * @param schema
- * @param md
- * @return
- * @throws Exception
- */
- @Override
- public String extractDateModified(String schema, Element md) throws Exception {
- Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_DATE_MODIFIED);
- String dateMod = Xml.transform(md, styleSheet).getText().trim();
-
- if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
- Log.debug(Geonet.DATA_MANAGER, "Extracted Date Modified '" + dateMod + "' for schema '" + schema + "'");
-
- // --- needed to detach md from the document
- md.detach();
-
- return dateMod;
- }
-
- /**
- *
- * @param schema
- * @param uuid
- * @param md
- * @return
- * @throws Exception
- */
- @Override
- public Element setUUID(String schema, String uuid, Element md) throws Exception {
- // --- setup environment
-
- Element env = new Element("env");
- env.addContent(new Element("uuid").setText(uuid));
-
- // --- setup root element
-
- Element root = new Element("root");
- root.addContent(md.detach());
- root.addContent(env.detach());
-
- // --- do an XSL transformation
-
- Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.SET_UUID);
-
- return Xml.transform(root, styleSheet);
- }
-
- /**
- *
- * @param md
- * @return
- * @throws Exception
- */
- @Override
- public Element extractSummary(Element md) throws Exception {
- Path styleSheet = stylePath.resolve(Geonet.File.METADATA_BRIEF);
- Element summary = Xml.transform(md, styleSheet);
- if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
- Log.debug(Geonet.DATA_MANAGER, "Extracted summary '\n" + Xml.getString(summary));
-
- // --- needed to detach md from the document
- md.detach();
-
- return summary;
- }
-
- /**
- *
- * @param uuid
- * @return
- * @throws Exception
- */
- @Override
- public @Nullable String getMetadataId(@Nonnull String uuid) throws Exception {
- final List idList = findAllIdsBy(hasMetadataUuid(uuid));
- if (idList.isEmpty()) {
- return null;
- }
- return String.valueOf(idList.get(0));
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public List findAllIdsBy(Specification extends AbstractMetadata> specs) {
- try {
- return metadataRepository.findAllIdsBy((Specification) specs);
- } catch (Throwable t) {
- // Maybe it is not a Specification
- }
- throw new NotImplementedException("Unknown IMetadata subtype: " + specs.getClass().getName());
- }
-
- /**
- *
- * @param id
- * @return
- */
- @Override
- public String getVersion(String id) {
- return metadataManager.getEditLib().getVersion(id);
- }
-
- /**
- *
- * @param id
- * @return
- */
- @Override
- public String getNewVersion(String id) {
- return metadataManager.getEditLib().getNewVersion(id);
- }
-
- @Override
- public void setTemplate(final int id, final MetadataType type, final String title) throws Exception {
- setTemplateExt(id, type);
- metadataIndexer.indexMetadata(Integer.toString(id), true, null);
- }
-
- @Override
- public void setTemplateExt(final int id, final MetadataType metadataType) throws Exception {
- metadataRepository.update(id, new Updater() {
- @Override
- public void apply(@Nonnull Metadata metadata) {
- final MetadataDataInfo dataInfo = metadata.getDataInfo();
- dataInfo.setType(metadataType);
- }
- });
- }
-
- @Override
- public void setHarvested(int id, String harvestUuid) throws Exception {
- setHarvestedExt(id, harvestUuid);
- metadataIndexer.indexMetadata(Integer.toString(id), true, null);
- }
-
- /**
- * Set metadata type to subtemplate and set the title. Only subtemplates need to
- * persist the title as it is used to give a meaningful title for use when
- * offering the subtemplate to users in the editor.
- *
- * @param id
- * Metadata id to set to type subtemplate
- * @param title
- * Title of metadata of subtemplate/fragment
- */
- @Override
- public void setSubtemplateTypeAndTitleExt(final int id, String title) throws Exception {
- metadataRepository.update(id, new Updater() {
- @Override
- public void apply(@Nonnull Metadata metadata) {
- final MetadataDataInfo dataInfo = metadata.getDataInfo();
- dataInfo.setType(MetadataType.SUB_TEMPLATE);
- if (title != null) {
- dataInfo.setTitle(title);
- }
- }
- });
- }
-
- @Override
- public void setHarvestedExt(int id, String harvestUuid) throws Exception {
- setHarvestedExt(id, harvestUuid, Optional.absent());
- }
-
- @Override
- public void setHarvestedExt(final int id, final String harvestUuid, final Optional harvestUri)
- throws Exception {
- metadataRepository.update(id, new Updater() {
- @Override
- public void apply(Metadata metadata) {
- MetadataHarvestInfo harvestInfo = metadata.getHarvestInfo();
- harvestInfo.setUuid(harvestUuid);
- harvestInfo.setHarvested(harvestUuid != null);
- harvestInfo.setUri(harvestUri.orNull());
- }
- });
- }
-
- /**
- *
- * @param id
- * @param displayOrder
- * @throws Exception
- */
- @Override
- public void updateDisplayOrder(final String id, final String displayOrder) throws Exception {
- metadataRepository.update(Integer.valueOf(id), new Updater() {
- @Override
- public void apply(Metadata entity) {
- entity.getDataInfo().setDisplayOrder(Integer.parseInt(displayOrder));
- }
- });
- }
-
- /**
- * @throws Exception
- * hmm
- */
- @Override
- public void increasePopularity(ServiceContext srvContext, String id) throws Exception {
- // READONLYMODE
- if (!srvContext.getBean(NodeInfo.class).isReadOnly()) {
- // Update the popularity in database
- int iId = Integer.parseInt(id);
- metadataRepository.incrementPopularity(iId);
-
- // And register the metadata to be indexed in the near future
- final IndexingList list = srvContext.getBean(IndexingList.class);
- list.add(iId);
- } else {
- if (Log.isDebugEnabled(Geonet.DATA_MANAGER)) {
- Log.debug(Geonet.DATA_MANAGER,
- "GeoNetwork is operating in read-only mode. IncreasePopularity is skipped.");
- }
- }
- }
-
- /**
- * Rates a metadata.
- *
- * @param ipAddress
- * ipAddress IP address of the submitting client
- * @param rating
- * range should be 1..5
- * @throws Exception
- * hmm
- */
- @Override
- public int rateMetadata(final int metadataId, final String ipAddress, final int rating) throws Exception {
- // Save rating for this IP
- MetadataRatingByIp ratingEntity = new MetadataRatingByIp();
- ratingEntity.setRating(rating);
- ratingEntity.setId(new MetadataRatingByIpId(metadataId, ipAddress));
-
- ratingByIpRepository.save(ratingEntity);
-
- // calculate new rating
- final int newRating = ratingByIpRepository.averageRating(metadataId);
-
- if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
- Log.debug(Geonet.DATA_MANAGER, "Setting rating for id:" + metadataId + " --> rating is:" + newRating);
-
- metadataRepository.update(metadataId, new Updater() {
- @Override
- public void apply(Metadata entity) {
- entity.getDataInfo().setRating(newRating);
- }
- });
- // And register the metadata to be indexed in the near future
- indexingList.add(metadataId);
-
- return rating;
- }
-
- /**
- * Retrieves a metadata (in xml) given its id with no geonet:info.
- */
- @SuppressWarnings("unchecked")
- @Override
- public Element getMetadataNoInfo(ServiceContext srvContext, String id) throws Exception {
- Element md = srvContext.getBean(IMetadataManager.class).getMetadata(srvContext, id, false, false, false);
- md.removeChild(Edit.RootChild.INFO, Edit.NAMESPACE);
-
- // Drop Geonet namespace declaration. It may be contained
- // multiple times, so loop on all.
- final List additionalNamespaces = new ArrayList(md.getAdditionalNamespaces());
- for (Namespace n : additionalNamespaces) {
- if (Edit.NAMESPACE.getURI().equals(n.getURI())) {
- md.removeNamespaceDeclaration(Edit.NAMESPACE);
- }
- }
- return md;
- }
-
- /**
- * Retrieves a metadata element given it's ref.
- */
- @Override
- public Element getElementByRef(Element md, String ref) {
- return metadataManager.getEditLib().findElement(md, ref);
- }
-
- /**
- * Returns true if the metadata exists in the database.
- */
- @Override
- public boolean existsMetadata(int id) throws Exception {
- return exists(id);
- }
-
- /**
- * Returns true if the metadata uuid exists in the database.
- */
- @Override
- public boolean existsMetadataUuid(String uuid) throws Exception {
- return !findAllIdsBy(hasMetadataUuid(uuid)).isEmpty();
- }
-
- /**
- * Returns all the keywords in the system.
- */
- @Override
- public Element getKeywords() throws Exception {
- // TODO ES
- // Collection keywords = getSearchManager().getTerms("keyword");
- Element el = new Element("keywords");
-
- // for (Object keyword : keywords) {
- // el.addContent(new Element("keyword").setText((String) keyword));
- // }
- return el;
- }
-
- /**
- *
- * @param metadataId
- * @return
- * @throws Exception
- */
- @Override
- public Element getThumbnails(ServiceContext context, String metadataId) throws Exception {
- Element md = getXmlSerializer().select(context, metadataId);
-
- if (md == null)
- return null;
-
- md.detach();
-
- String schema = metadataSchemaUtils.getMetadataSchema(metadataId);
-
- // --- do an XSL transformation
- Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_THUMBNAILS);
-
- Element result = Xml.transform(md, styleSheet);
- result.addContent(new Element("id").setText(metadataId));
-
- return result;
- }
-
- /**
- *
- * @param context
- * @param id
- * @param small
- * @param file
- * @throws Exception
- */
- @Override
- public void setThumbnail(ServiceContext context, String id, boolean small, String file, boolean indexAfterChange)
- throws Exception {
- int pos = file.lastIndexOf('.');
- String ext = (pos == -1) ? "???" : file.substring(pos + 1);
-
- Element env = new Element("env");
- env.addContent(new Element("file").setText(file));
- env.addContent(new Element("ext").setText(ext));
-
- String host = getSettingManager().getValue(Settings.SYSTEM_SERVER_HOST);
- String port = getSettingManager().getValue(Settings.SYSTEM_SERVER_PORT);
- String baseUrl = context.getBaseUrl();
-
- env.addContent(new Element("host").setText(host));
- env.addContent(new Element("port").setText(port));
- env.addContent(new Element("baseUrl").setText(baseUrl));
- // TODO: Remove host, port, baseUrl and simplify the
- // URL created in the XSLT. Keeping it for the time
- // as many profiles depend on it.
- env.addContent(new Element("url").setText(getSettingManager().getSiteURL(context)));
-
- manageThumbnail(context, id, small, env, Geonet.File.SET_THUMBNAIL, indexAfterChange);
- }
-
- /**
- *
- * @param context
- * @param id
- * @param small
- * @throws Exception
- */
- @Override
- public void unsetThumbnail(ServiceContext context, String id, boolean small, boolean indexAfterChange)
- throws Exception {
- Element env = new Element("env");
-
- manageThumbnail(context, id, small, env, Geonet.File.UNSET_THUMBNAIL, indexAfterChange);
- }
-
- /**
- *
- * @param context
- * @param id
- * @param small
- * @param env
- * @param styleSheet
- * @param indexAfterChange
- * @throws Exception
- */
- private void manageThumbnail(ServiceContext context, String id, boolean small, Element env, String styleSheet,
- boolean indexAfterChange) throws Exception {
- boolean forEditing = false, withValidationErrors = false, keepXlinkAttributes = true;
- Element md = context.getBean(IMetadataManager.class).getMetadata(context, id, forEditing, withValidationErrors,
- keepXlinkAttributes);
-
- if (md == null)
- return;
-
- md.detach();
-
- String schema = metadataSchemaUtils.getMetadataSchema(id);
-
- // --- setup environment
- String type = small ? "thumbnail" : "large_thumbnail";
- env.addContent(new Element("type").setText(type));
- transformMd(context, id, md, env, schema, styleSheet, indexAfterChange);
- }
-
- /**
- *
- * @param context
- * @param metadataId
- * @param md
- * @param env
- * @param schema
- * @param styleSheet
- * @param indexAfterChange
- * @throws Exception
- */
- private void transformMd(ServiceContext context, String metadataId, Element md, Element env, String schema,
- String styleSheet, boolean indexAfterChange) throws Exception {
-
- if (env.getChild("host") == null) {
- String host = getSettingManager().getValue(Settings.SYSTEM_SERVER_HOST);
- String port = getSettingManager().getValue(Settings.SYSTEM_SERVER_PORT);
- env.addContent(new Element("host").setText(host));
- env.addContent(new Element("port").setText(port));
- }
-
- // --- setup root element
- Element root = new Element("root");
- root.addContent(md);
- root.addContent(env);
-
- // --- do an XSL transformation
- Path styleSheetPath = metadataSchemaUtils.getSchemaDir(schema).resolve(styleSheet);
-
- md = Xml.transform(root, styleSheetPath);
- String changeDate = null;
- String uuid = null;
- if (schemaManager.getSchema(schema).isReadwriteUUID()) {
- uuid = extractUUID(schema, md);
- }
-
- getXmlSerializer().update(metadataId, md, changeDate, true, uuid, context);
-
- if (indexAfterChange) {
- // Notifies the metadata change to metatada notifier service
- notifyMetadataChange(md, metadataId);
-
- // --- update search criteria
- metadataIndexer.indexMetadata(metadataId, true, null);
- }
- }
-
- /**
- *
- * @param context
- * @param id
- * @param licenseurl
- * @param imageurl
- * @param jurisdiction
- * @param licensename
- * @param type
- * @throws Exception
- */
- @Override
- public void setDataCommons(ServiceContext context, String id, String licenseurl, String imageurl,
- String jurisdiction, String licensename, String type) throws Exception {
- Element env = prepareCommonsEnv(licenseurl, imageurl, jurisdiction, licensename, type);
- manageCommons(context, id, env, Geonet.File.SET_DATACOMMONS);
- }
-
- private Element prepareCommonsEnv(String licenseurl, String imageurl, String jurisdiction, String licensename,
- String type) {
- Element env = new Element("env");
- env.addContent(new Element("imageurl").setText(imageurl));
- env.addContent(new Element("licenseurl").setText(licenseurl));
- env.addContent(new Element("jurisdiction").setText(jurisdiction));
- env.addContent(new Element("licensename").setText(licensename));
- env.addContent(new Element("type").setText(type));
- return env;
- }
-
- /**
- *
- * @param context
- * @param id
- * @param licenseurl
- * @param imageurl
- * @param jurisdiction
- * @param licensename
- * @param type
- * @throws Exception
- */
- @Override
- public void setCreativeCommons(ServiceContext context, String id, String licenseurl, String imageurl,
- String jurisdiction, String licensename, String type) throws Exception {
- Element env = prepareCommonsEnv(licenseurl, imageurl, jurisdiction, licensename, type);
- manageCommons(context, id, env, Geonet.File.SET_CREATIVECOMMONS);
- }
-
- /**
- * Extract the title field from the Metadata Repository. This is only valid for
- * subtemplates as the title can be stored with the subtemplate (since
- * subtemplates don't have a title) - metadata records don't store the title
- * here as this is part of the metadata.
- *
- * @param id
- * metadata id to retrieve
- */
- @Override
- public String getMetadataTitle(String id) throws Exception {
- AbstractMetadata md = findOne(id);
-
- if (md == null) {
- throw new IllegalArgumentException("Metadata not found for id : " + id);
- } else {
- // get metadata title
- return md.getDataInfo().getTitle();
- }
- }
-
- /**
- *
- * @param context
- * @param id
- * @param env
- * @param styleSheet
- * @throws Exception
- */
- private void manageCommons(ServiceContext context, String id, Element env, String styleSheet) throws Exception {
- Lib.resource.checkEditPrivilege(context, id);
- Element md = getXmlSerializer().select(context, id);
-
- if (md == null)
- return;
-
- md.detach();
-
- String schema = metadataSchemaUtils.getMetadataSchema(id);
- transformMd(context, id, md, env, schema, styleSheet, true);
- }
-
- private XmlSerializer getXmlSerializer() {
- return xmlSerializer;
- }
-
- private SettingManager getSettingManager() {
- return this.settingManager;
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public long count(Specification extends AbstractMetadata> specs) {
- try {
- return metadataRepository.count((Specification) specs);
- } catch (Throwable t) {
- // Maybe it is not a Specification
- }
- throw new NotImplementedException("Unknown IMetadata subtype: " + specs.getClass().getName());
- }
-
- @Override
- public long count() {
- return metadataRepository.count();
- }
-
- @Override
- public AbstractMetadata findOne(int id) {
- return metadataRepository.findOne(id);
- }
-
- @Override
- public AbstractMetadata findOneByUuid(String uuid) {
- return metadataRepository.findOneByUuid(uuid);
- }
-
- @Override
- public AbstractMetadata findOne(Specification spec) {
- return metadataRepository.findOne(spec);
- }
-
- @Override
- public AbstractMetadata findOne(String id) {
- return metadataRepository.findOne(id);
- }
-
- @Override
- public List extends AbstractMetadata> findAllByHarvestInfo_Uuid(String uuid) {
- return metadataRepository.findAllByHarvestInfo_Uuid(uuid);
- }
-
- @Override
- public Iterable extends AbstractMetadata> findAll(Set keySet) {
- return metadataRepository.findAll(keySet);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public List extends AbstractMetadata> findAll(Specification extends AbstractMetadata> specs) {
- try {
- return metadataRepository.findAll((Specification) specs);
- } catch (Throwable t) {
- // Maybe it is not a Specification
- }
- throw new NotImplementedException("Unknown IMetadata subtype: " + specs.getClass().getName());
- }
-
- @Override
- public List findAllSimple(String harvestUuid) {
- return metadataRepository.findAllSimple(harvestUuid);
- }
-
- @Override
- public boolean exists(Integer iId) {
- return metadataRepository.exists(iId);
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Element findAllAsXml(Specification extends AbstractMetadata> specs, Sort sortByChangeDateDesc) {
- try {
- return metadataRepository.findAllAsXml((Specification) specs, sortByChangeDateDesc);
- } catch (Throwable t) {
- // Maybe it is not a Specification
- }
- throw new NotImplementedException("Unknown IMetadata subtype: " + specs.getClass().getName());
- }
-
- @Override
- public MetadataReportsQueries getMetadataReports() {
- return metadataRepository.getMetadataReports();
- }
-
- @SuppressWarnings("unchecked")
- @Override
- public Element findAllAsXml(@Nullable Specification extends AbstractMetadata> specs,
- @Nullable Pageable pageable) {
- try {
- return metadataRepository.findAllAsXml((Specification) specs, pageable);
- } catch (Throwable t) {
- // Maybe it is not a Specification
- }
- throw new NotImplementedException("Unknown IMetadata subtype: " + specs.getClass().getName());
- }
-
- protected MetadataRepository getMetadataRepository() {
- return metadataRepository;
- }
-
- protected SchemaManager getSchemaManager() {
- return schemaManager;
- }
-
- @Override
- public boolean checkMetadataWithSameUuidExist(String uuid, int id) {
- // Check if another record exist with that UUID
- Metadata recordWithThatUuid = getMetadataRepository().findOneByUuid(uuid);
- if (recordWithThatUuid != null && recordWithThatUuid.getId() != id) {
- // If yes, this would have triggered a DataIntegrityViolationException
- throw new IllegalArgumentException(String.format(
- "Another record exist with UUID '%s'. This record as internal id '%d'. The record you're trying to update with id '%d' can not be saved.",
- uuid, recordWithThatUuid.getId(), id));
- }
- return false;
- }
+ * @param schema
+ * @param md
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public String extractDateModified(String schema, Element md) throws Exception {
+ Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_DATE_MODIFIED);
+ String dateMod = Xml.transform(md, styleSheet).getText().trim();
+
+ if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
+ Log.debug(Geonet.DATA_MANAGER, "Extracted Date Modified '" + dateMod + "' for schema '" + schema + "'");
+
+ // --- needed to detach md from the document
+ md.detach();
+
+ return dateMod;
+ }
+
+ /**
+ * @param schema
+ * @param uuid
+ * @param md
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public Element setUUID(String schema, String uuid, Element md) throws Exception {
+ // --- setup environment
+
+ Element env = new Element("env");
+ env.addContent(new Element("uuid").setText(uuid));
+
+ // --- setup root element
+
+ Element root = new Element("root");
+ root.addContent(md.detach());
+ root.addContent(env.detach());
+
+ // --- do an XSL transformation
+
+ Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.SET_UUID);
+
+ return Xml.transform(root, styleSheet);
+ }
+
+ /**
+ * @param md
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public Element extractSummary(Element md) throws Exception {
+ Path styleSheet = stylePath.resolve(Geonet.File.METADATA_BRIEF);
+ Element summary = Xml.transform(md, styleSheet);
+ if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
+ Log.debug(Geonet.DATA_MANAGER, "Extracted summary '\n" + Xml.getString(summary));
+
+ // --- needed to detach md from the document
+ md.detach();
+
+ return summary;
+ }
+
+ /**
+ * @param uuid
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public @Nullable
+ String getMetadataId(@Nonnull String uuid) throws Exception {
+ final List idList = findAllIdsBy(hasMetadataUuid(uuid));
+ if (idList.isEmpty()) {
+ return null;
+ }
+ return String.valueOf(idList.get(0));
+ }
+
+ @Override
+ public List findAllIdsBy(Specification extends AbstractMetadata> specs) {
+ try {
+ return metadataRepository.findAllIdsBy((Specification) specs);
+ } catch (ClassCastException t) {
+ // Maybe it is not a Specification
+ }
+
+ return Collections.emptyList();
+ }
+
+ /**
+ * @param id
+ * @return
+ */
+ @Override
+ public String getVersion(String id) {
+ return metadataManager.getEditLib().getVersion(id);
+ }
+
+ /**
+ * @param id
+ * @return
+ */
+ @Override
+ public String getNewVersion(String id) {
+ return metadataManager.getEditLib().getNewVersion(id);
+ }
+
+ @Override
+ public void setTemplate(final int id, final MetadataType type, final String title) throws Exception {
+ setTemplateExt(id, type);
+ metadataIndexer.indexMetadata(Integer.toString(id), true, null);
+ }
+
+ @Override
+ public void setTemplateExt(final int id, final MetadataType metadataType) throws Exception {
+ metadataRepository.update(id, new Updater() {
+ @Override
+ public void apply(@Nonnull Metadata metadata) {
+ final MetadataDataInfo dataInfo = metadata.getDataInfo();
+ dataInfo.setType(metadataType);
+ }
+ });
+ }
+
+ @Override
+ public void setHarvested(int id, String harvestUuid) throws Exception {
+ setHarvestedExt(id, harvestUuid);
+ metadataIndexer.indexMetadata(Integer.toString(id), true, null);
+ }
+
+ /**
+ * Set metadata type to subtemplate and set the title. Only subtemplates need to
+ * persist the title as it is used to give a meaningful title for use when
+ * offering the subtemplate to users in the editor.
+ *
+ * @param id Metadata id to set to type subtemplate
+ * @param title Title of metadata of subtemplate/fragment
+ */
+ @Override
+ public void setSubtemplateTypeAndTitleExt(final int id, String title) throws Exception {
+ metadataRepository.update(id, new Updater() {
+ @Override
+ public void apply(@Nonnull Metadata metadata) {
+ final MetadataDataInfo dataInfo = metadata.getDataInfo();
+ dataInfo.setType(MetadataType.SUB_TEMPLATE);
+ if (title != null) {
+ dataInfo.setTitle(title);
+ }
+ }
+ });
+ }
+
+ @Override
+ public void setHarvestedExt(int id, String harvestUuid) throws Exception {
+ setHarvestedExt(id, harvestUuid, Optional.absent());
+ }
+
+ @Override
+ public void setHarvestedExt(final int id, final String harvestUuid, final Optional harvestUri)
+ throws Exception {
+ metadataRepository.update(id, new Updater() {
+ @Override
+ public void apply(Metadata metadata) {
+ MetadataHarvestInfo harvestInfo = metadata.getHarvestInfo();
+ harvestInfo.setUuid(harvestUuid);
+ harvestInfo.setHarvested(harvestUuid != null);
+ harvestInfo.setUri(harvestUri.orNull());
+ }
+ });
+ }
+
+ /**
+ * @param id
+ * @param displayOrder
+ * @throws Exception
+ */
+ @Override
+ public void updateDisplayOrder(final String id, final String displayOrder) throws Exception {
+ metadataRepository.update(Integer.valueOf(id), new Updater() {
+ @Override
+ public void apply(Metadata entity) {
+ entity.getDataInfo().setDisplayOrder(Integer.parseInt(displayOrder));
+ }
+ });
+ }
+
+ /**
+ * @throws Exception hmm
+ */
+ @Override
+ public void increasePopularity(ServiceContext srvContext, String id) throws Exception {
+ // READONLYMODE
+ if (!srvContext.getBean(NodeInfo.class).isReadOnly()) {
+ // Update the popularity in database
+ int iId = Integer.parseInt(id);
+ metadataRepository.incrementPopularity(iId);
+
+ // And register the metadata to be indexed in the near future
+ final IndexingList list = srvContext.getBean(IndexingList.class);
+ list.add(iId);
+ } else {
+ if (Log.isDebugEnabled(Geonet.DATA_MANAGER)) {
+ Log.debug(Geonet.DATA_MANAGER,
+ "GeoNetwork is operating in read-only mode. IncreasePopularity is skipped.");
+ }
+ }
+ }
+
+ /**
+ * Rates a metadata.
+ *
+ * @param ipAddress ipAddress IP address of the submitting client
+ * @param rating range should be 1..5
+ * @throws Exception hmm
+ */
+ @Override
+ public int rateMetadata(final int metadataId, final String ipAddress, final int rating) throws Exception {
+ // Save rating for this IP
+ MetadataRatingByIp ratingEntity = new MetadataRatingByIp();
+ ratingEntity.setRating(rating);
+ ratingEntity.setId(new MetadataRatingByIpId(metadataId, ipAddress));
+
+ ratingByIpRepository.save(ratingEntity);
+
+ // calculate new rating
+ final int newRating = ratingByIpRepository.averageRating(metadataId);
+
+ if (Log.isDebugEnabled(Geonet.DATA_MANAGER))
+ Log.debug(Geonet.DATA_MANAGER, "Setting rating for id:" + metadataId + " --> rating is:" + newRating);
+
+ metadataRepository.update(metadataId, new Updater() {
+ @Override
+ public void apply(Metadata entity) {
+ entity.getDataInfo().setRating(newRating);
+ }
+ });
+ // And register the metadata to be indexed in the near future
+ indexingList.add(metadataId);
+
+ return rating;
+ }
+
+ /**
+ * Retrieves a metadata (in xml) given its id with no geonet:info.
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ public Element getMetadataNoInfo(ServiceContext srvContext, String id) throws Exception {
+ Element md = srvContext.getBean(IMetadataManager.class).getMetadata(srvContext, id, false, false, false);
+ md.removeChild(Edit.RootChild.INFO, Edit.NAMESPACE);
+
+ // Drop Geonet namespace declaration. It may be contained
+ // multiple times, so loop on all.
+ final List additionalNamespaces = new ArrayList(md.getAdditionalNamespaces());
+ for (Namespace n : additionalNamespaces) {
+ if (Edit.NAMESPACE.getURI().equals(n.getURI())) {
+ md.removeNamespaceDeclaration(Edit.NAMESPACE);
+ }
+ }
+ return md;
+ }
+
+ /**
+ * Retrieves a metadata element given it's ref.
+ */
+ @Override
+ public Element getElementByRef(Element md, String ref) {
+ return metadataManager.getEditLib().findElement(md, ref);
+ }
+
+ /**
+ * Returns true if the metadata exists in the database.
+ */
+ @Override
+ public boolean existsMetadata(int id) throws Exception {
+ return exists(id);
+ }
+
+ /**
+ * Returns true if the metadata uuid exists in the database.
+ */
+ @Override
+ public boolean existsMetadataUuid(String uuid) throws Exception {
+ return !findAllIdsBy(hasMetadataUuid(uuid)).isEmpty();
+ }
+
+ /**
+ * Returns all the keywords in the system.
+ */
+ @Override
+ public Element getKeywords() throws Exception {
+ // TODO ES
+ // Collection keywords = getSearchManager().getTerms("keyword");
+ Element el = new Element("keywords");
+
+ // for (Object keyword : keywords) {
+ // el.addContent(new Element("keyword").setText((String) keyword));
+ // }
+ return el;
+ }
+
+ /**
+ * @param metadataId
+ * @return
+ * @throws Exception
+ */
+ @Override
+ public Element getThumbnails(ServiceContext context, String metadataId) throws Exception {
+ Element md = getXmlSerializer().select(context, metadataId);
+
+ if (md == null)
+ return null;
+
+ md.detach();
+
+ String schema = metadataSchemaUtils.getMetadataSchema(metadataId);
+
+ // --- do an XSL transformation
+ Path styleSheet = metadataSchemaUtils.getSchemaDir(schema).resolve(Geonet.File.EXTRACT_THUMBNAILS);
+
+ Element result = Xml.transform(md, styleSheet);
+ result.addContent(new Element("id").setText(metadataId));
+
+ return result;
+ }
+
+ /**
+ * @param context
+ * @param id
+ * @param small
+ * @param file
+ * @throws Exception
+ */
+ @Override
+ public void setThumbnail(ServiceContext context, String id, boolean small, String file, boolean indexAfterChange)
+ throws Exception {
+ int pos = file.lastIndexOf('.');
+ String ext = (pos == -1) ? "???" : file.substring(pos + 1);
+
+ Element env = new Element("env");
+ env.addContent(new Element("file").setText(file));
+ env.addContent(new Element("ext").setText(ext));
+
+ String host = getSettingManager().getValue(Settings.SYSTEM_SERVER_HOST);
+ String port = getSettingManager().getValue(Settings.SYSTEM_SERVER_PORT);
+ String baseUrl = context.getBaseUrl();
+
+ env.addContent(new Element("host").setText(host));
+ env.addContent(new Element("port").setText(port));
+ env.addContent(new Element("baseUrl").setText(baseUrl));
+ // TODO: Remove host, port, baseUrl and simplify the
+ // URL created in the XSLT. Keeping it for the time
+ // as many profiles depend on it.
+ env.addContent(new Element("url").setText(getSettingManager().getSiteURL(context)));
+
+ manageThumbnail(context, id, small, env, Geonet.File.SET_THUMBNAIL, indexAfterChange);
+ }
+
+ /**
+ * @param context
+ * @param id
+ * @param small
+ * @throws Exception
+ */
+ @Override
+ public void unsetThumbnail(ServiceContext context, String id, boolean small, boolean indexAfterChange)
+ throws Exception {
+ Element env = new Element("env");
+
+ manageThumbnail(context, id, small, env, Geonet.File.UNSET_THUMBNAIL, indexAfterChange);
+ }
+
+ /**
+ * @param context
+ * @param id
+ * @param small
+ * @param env
+ * @param styleSheet
+ * @param indexAfterChange
+ * @throws Exception
+ */
+ private void manageThumbnail(ServiceContext context, String id, boolean small, Element env, String styleSheet,
+ boolean indexAfterChange) throws Exception {
+ boolean forEditing = false, withValidationErrors = false, keepXlinkAttributes = true;
+ Element md = context.getBean(IMetadataManager.class).getMetadata(context, id, forEditing, withValidationErrors,
+ keepXlinkAttributes);
+
+ if (md == null)
+ return;
+
+ md.detach();
+
+ String schema = metadataSchemaUtils.getMetadataSchema(id);
+
+ // --- setup environment
+ String type = small ? "thumbnail" : "large_thumbnail";
+ env.addContent(new Element("type").setText(type));
+ transformMd(context, id, md, env, schema, styleSheet, indexAfterChange);
+ }
+
+ /**
+ * @param context
+ * @param metadataId
+ * @param md
+ * @param env
+ * @param schema
+ * @param styleSheet
+ * @param indexAfterChange
+ * @throws Exception
+ */
+ private void transformMd(ServiceContext context, String metadataId, Element md, Element env, String schema,
+ String styleSheet, boolean indexAfterChange) throws Exception {
+
+ if (env.getChild("host") == null) {
+ String host = getSettingManager().getValue(Settings.SYSTEM_SERVER_HOST);
+ String port = getSettingManager().getValue(Settings.SYSTEM_SERVER_PORT);
+ env.addContent(new Element("host").setText(host));
+ env.addContent(new Element("port").setText(port));
+ }
+
+ // --- setup root element
+ Element root = new Element("root");
+ root.addContent(md);
+ root.addContent(env);
+
+ // --- do an XSL transformation
+ Path styleSheetPath = metadataSchemaUtils.getSchemaDir(schema).resolve(styleSheet);
+
+ md = Xml.transform(root, styleSheetPath);
+ String changeDate = null;
+ String uuid = null;
+ if (schemaManager.getSchema(schema).isReadwriteUUID()) {
+ uuid = extractUUID(schema, md);
+ }
+
+ getXmlSerializer().update(metadataId, md, changeDate, true, uuid, context);
+
+ if (indexAfterChange) {
+ // Notifies the metadata change to metatada notifier service
+ notifyMetadataChange(md, metadataId);
+
+ // --- update search criteria
+ metadataIndexer.indexMetadata(metadataId, true, null);
+ }
+ }
+
+ /**
+ * @param context
+ * @param id
+ * @param licenseurl
+ * @param imageurl
+ * @param jurisdiction
+ * @param licensename
+ * @param type
+ * @throws Exception
+ */
+ @Override
+ public void setDataCommons(ServiceContext context, String id, String licenseurl, String imageurl,
+ String jurisdiction, String licensename, String type) throws Exception {
+ Element env = prepareCommonsEnv(licenseurl, imageurl, jurisdiction, licensename, type);
+ manageCommons(context, id, env, Geonet.File.SET_DATACOMMONS);
+ }
+
+ private Element prepareCommonsEnv(String licenseurl, String imageurl, String jurisdiction, String licensename,
+ String type) {
+ Element env = new Element("env");
+ env.addContent(new Element("imageurl").setText(imageurl));
+ env.addContent(new Element("licenseurl").setText(licenseurl));
+ env.addContent(new Element("jurisdiction").setText(jurisdiction));
+ env.addContent(new Element("licensename").setText(licensename));
+ env.addContent(new Element("type").setText(type));
+ return env;
+ }
+
+ /**
+ * @param context
+ * @param id
+ * @param licenseurl
+ * @param imageurl
+ * @param jurisdiction
+ * @param licensename
+ * @param type
+ * @throws Exception
+ */
+ @Override
+ public void setCreativeCommons(ServiceContext context, String id, String licenseurl, String imageurl,
+ String jurisdiction, String licensename, String type) throws Exception {
+ Element env = prepareCommonsEnv(licenseurl, imageurl, jurisdiction, licensename, type);
+ manageCommons(context, id, env, Geonet.File.SET_CREATIVECOMMONS);
+ }
+
+ /**
+ * Extract the title field from the Metadata Repository. This is only valid for
+ * subtemplates as the title can be stored with the subtemplate (since
+ * subtemplates don't have a title) - metadata records don't store the title
+ * here as this is part of the metadata.
+ *
+ * @param id metadata id to retrieve
+ */
+ @Override
+ public String getMetadataTitle(String id) throws Exception {
+ AbstractMetadata md = findOne(id);
+
+ if (md == null) {
+ throw new IllegalArgumentException("Metadata not found for id : " + id);
+ } else {
+ // get metadata title
+ return md.getDataInfo().getTitle();
+ }
+ }
+
+ /**
+ * @param context
+ * @param id
+ * @param env
+ * @param styleSheet
+ * @throws Exception
+ */
+ private void manageCommons(ServiceContext context, String id, Element env, String styleSheet) throws Exception {
+ Lib.resource.checkEditPrivilege(context, id);
+ Element md = getXmlSerializer().select(context, id);
+
+ if (md == null)
+ return;
+
+ md.detach();
+
+ String schema = metadataSchemaUtils.getMetadataSchema(id);
+ transformMd(context, id, md, env, schema, styleSheet, true);
+ }
+
+ private XmlSerializer getXmlSerializer() {
+ return xmlSerializer;
+ }
+
+ private SettingManager getSettingManager() {
+ return this.settingManager;
+ }
+
+ @Override
+ public long count(Specification extends AbstractMetadata> specs) {
+ try {
+ return metadataRepository.count((Specification) specs);
+ } catch (Throwable t) {
+ // Maybe it is not a Specification
+ }
+ throw new NotImplementedException("Unknown IMetadata subtype: " + specs.getClass().getName());
+ }
+
+ @Override
+ public long count() {
+ return metadataRepository.count();
+ }
+
+ @Override
+ public AbstractMetadata findOne(int id) {
+ return metadataRepository.findOne(id);
+ }
+
+ @Override
+ public AbstractMetadata findOneByUuid(String uuid) {
+ AbstractMetadata metadata = null;
+ try {
+ metadata = metadataRepository.findOneByUuid(uuid);
+ } catch (IncorrectResultSizeDataAccessException e){
+ Log.warning(Geonet.GEONETWORK, String.format(
+ "More than one record found with UUID '%s'. Error is '%s'.",
+ uuid, e.getMessage()));
+ }
+ return metadata;
+ }
+
+ @Override
+ public List extends AbstractMetadata> findAllByUuid(String uuid) {
+ return metadataRepository.findAllByUuid(uuid);
+ }
+
+ @Override
+ public AbstractMetadata findOne(Specification extends AbstractMetadata> spec) {
+ try {
+ return metadataRepository.findOne((Specification) spec);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + spec.getClass().getName());
+ }
+ }
+
+ @Override
+ public AbstractMetadata findOne(String id) {
+ return metadataRepository.findOne(id);
+ }
+
+ @Override
+ public List extends AbstractMetadata> findAllByHarvestInfo_Uuid(String uuid) {
+ return metadataRepository.findAllByHarvestInfo_Uuid(uuid);
+ }
+
+ @Override
+ public Iterable extends AbstractMetadata> findAll(Set keySet) {
+ return metadataRepository.findAll(keySet);
+ }
+
+ @Override
+ public List extends AbstractMetadata> findAll(Specification extends AbstractMetadata> spec, Sort order) {
+ return metadataRepository.findAll((Specification) spec, order);
+ }
+
+ @Override
+ public List extends AbstractMetadata> findAll(Specification extends AbstractMetadata> specs) {
+ try {
+ return metadataRepository.findAll((Specification) specs);
+ } catch (Throwable t) {
+ // Maybe it is not a Specification
+ }
+ throw new NotImplementedException("Unknown AbstractMetadata subtype: " + specs.getClass().getName());
+ }
+
+ @Override
+ public List findAllSimple(String harvestUuid) {
+ return metadataRepository.findAllSimple(harvestUuid);
+ }
+
+ @Override
+ public boolean exists(Integer iId) {
+ return metadataRepository.exists(iId);
+ }
+
+ @Override
+ public Element findAllAsXml(Specification extends AbstractMetadata> specs, Sort sortByChangeDateDesc) {
+ try {
+ return metadataRepository.findAllAsXml((Specification) specs, sortByChangeDateDesc);
+
+ } catch (Throwable t) {
+ // Maybe it is not a Specification
+ }
+ throw new NotImplementedException("Unknown AbstractMetadata subtype: " + specs.getClass().getName());
+ }
+
+ @Override
+ public MetadataReportsQueries getMetadataReports() {
+ return metadataRepository.getMetadataReports();
+ }
+
+ @Override
+ public Element findAllAsXml(@Nullable Specification extends AbstractMetadata> specs,
+ @Nullable Pageable pageable) {
+ try {
+ return metadataRepository.findAllAsXml((Specification) specs, pageable);
+ } catch (Throwable t) {
+ // Maybe it is not a Specification
+ }
+ throw new NotImplementedException("Unknown AbstractMetadata subtype: " + specs.getClass().getName());
+ }
+
+ protected MetadataRepository getMetadataRepository() {
+ return metadataRepository;
+ }
+
+ protected SchemaManager getSchemaManager() {
+ return schemaManager;
+ }
+
+ @Override
+ public boolean checkMetadataWithSameUuidExist(String uuid, int id) {
+ // Check if another record exist with that UUID
+ Metadata recordWithThatUuid = getMetadataRepository().findOneByUuid(uuid);
+ if (recordWithThatUuid != null && recordWithThatUuid.getId() != id) {
+ // If yes, this would have triggered a DataIntegrityViolationException
+ throw new IllegalArgumentException(String.format(
+ "Another record exist with UUID '%s'. This record as internal id '%d'. The record you're trying to update with id '%d' can not be saved.",
+ uuid, recordWithThatUuid.getId(), id));
+ }
+ return false;
+ }
+
+ @Override
+ public Page> findAllIdsAndChangeDates(Pageable pageable) {
+ return metadataRepository.findAllIdsAndChangeDates(pageable);
+ }
+
+ @Override
+ public Map findAllSourceInfo(Specification extends AbstractMetadata> spec) {
+ try {
+ return metadataRepository.findAllSourceInfo((Specification) spec);
+ } catch (Throwable t) {
+ // Maybe it is not a Specification
+ }
+ throw new NotImplementedException("Unknown AbstractMetadata subtype: " + spec.getClass().getName());
+ }
}
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataValidator.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataValidator.java
index 1cee711f235..6fa07316b00 100644
--- a/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataValidator.java
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/base/BaseMetadataValidator.java
@@ -1,3 +1,26 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
package org.fao.geonet.kernel.datamanager.base;
import jeeves.server.UserSession;
@@ -22,6 +45,7 @@
import org.fao.geonet.kernel.schema.MetadataSchema;
import org.fao.geonet.kernel.setting.SettingManager;
import org.fao.geonet.repository.MetadataValidationRepository;
+import org.fao.geonet.utils.Log;
import org.fao.geonet.utils.Xml;
import org.fao.geonet.utils.XmlErrorHandler;
import org.jdom.Attribute;
@@ -109,17 +133,17 @@ public void validateMetadata(String schema, Element xml, ServiceContext context,
theNSs.add(Namespace.getNamespace("svrl", "http://purl.oclc.org/dsdl/svrl"));
List> informationalReports = Xml.selectNodes(schemaTronReport,
- "geonet:report[@geonet:required != '" + SchematronRequirement.REQUIRED + "']", theNSs);
+ "geonet:report[@geonet:required != '" + SchematronRequirement.REQUIRED + "']", theNSs);
for (Object informationalReport : informationalReports) {
((Element) informationalReport).detach();
}
List> failedAssert = Xml.selectNodes(schemaTronReport,
- "geonet:report[@geonet:required = '" + SchematronRequirement.REQUIRED + "']/svrl:schematron-output/svrl:failed-assert",
- theNSs);
+ "geonet:report[@geonet:required = '" + SchematronRequirement.REQUIRED + "']/svrl:schematron-output/svrl:failed-assert",
+ theNSs);
List> failedSchematronVerification = Xml.selectNodes(schemaTronReport,
- "geonet:report[@geonet:required = '" + SchematronRequirement.REQUIRED + "']/geonet:schematronVerificationError",
- theNSs);
+ "geonet:report[@geonet:required = '" + SchematronRequirement.REQUIRED + "']/geonet:schematronVerificationError",
+ theNSs);
if ((!failedAssert.isEmpty()) || (!failedSchematronVerification.isEmpty())) {
StringBuilder errorReport = new StringBuilder();
@@ -164,7 +188,7 @@ public void validateMetadata(String schema, Element xml, ServiceContext context,
}
throw new SchematronValidationErrorEx(
- "Schematron errors detected for file " + fileName + " - " + errorReport + " for more details", schemaTronReport);
+ "Schematron errors detected for file " + fileName + " - " + errorReport + " for more details", schemaTronReport);
}
}
@@ -209,6 +233,12 @@ public void setNamespacePrefix(final Element md, final Namespace ns) {
*/
@Override
public void validate(String schema, Element md) throws Exception {
+
+ if (Log.isTraceEnabled(Geonet.DATA_MANAGER)) {
+ Log.trace(Geonet.DATA_MANAGER, "Validating record ");
+ Log.trace(Geonet.DATA_MANAGER, (new org.jdom.output.XMLOutputter()).outputString(md));
+ }
+
XmlErrorHandler eh = new XmlErrorHandler();
Element xsdErrors = validateInfo(schema, md, eh);
if (xsdErrors != null) {
@@ -289,7 +319,7 @@ public Element buildErrorReport(String type, String errorCode, String message, S
* Creates XML schematron report for each set of rules defined in schema directory.
*/
private Element getSchemaTronXmlReport(String schema, Element md, String lang, Map valTypeAndStatus)
- throws Exception {
+ throws Exception {
// NOTE: this method assumes that you've run enumerateTree on the metadata
MetadataSchema metadataSchema = metadataSchemaUtils.getSchema(schema);
@@ -328,7 +358,7 @@ private Element getSchemaTronXmlReport(String schema, Element md, String lang, M
faileAssertElements.next();
invalidRules++;
}
- Integer[] results = { invalidRules != 0 ? 0 : 1, firedRules, invalidRules };
+ Integer[] results = {invalidRules != 0 ? 0 : 1, firedRules, invalidRules};
if (valTypeAndStatus != null) {
valTypeAndStatus.put(ruleId, results);
}
@@ -354,7 +384,7 @@ private Element getSchemaTronXmlReport(String schema, Element md, String lang, M
* Used by harvesters that need to validate metadata.
*
* @param metadata metadata
- * @param lang Language from context
+ * @param lang Language from context
*/
@Override
public boolean doValidate(AbstractMetadata metadata, String lang) {
@@ -380,13 +410,13 @@ public boolean doValidate(AbstractMetadata metadata, String lang) {
}
if (xsdErrorCount > 0) {
validations.add(new MetadataValidation().setId(new MetadataValidationId(metadataId, "xsd"))
- .setStatus(MetadataValidationStatus.INVALID).setRequired(true).setNumTests(xsdErrorCount)
- .setNumFailures(xsdErrorCount));
+ .setStatus(MetadataValidationStatus.INVALID).setRequired(true).setNumTests(xsdErrorCount)
+ .setNumFailures(xsdErrorCount));
LOGGER.debug("Invalid.");
valid = false;
} else {
validations.add(new MetadataValidation().setId(new MetadataValidationId(metadataId, "xsd"))
- .setStatus(MetadataValidationStatus.VALID).setRequired(true).setNumTests(1).setNumFailures(0));
+ .setStatus(MetadataValidationStatus.VALID).setRequired(true).setNumTests(1).setNumFailures(0));
LOGGER.debug("Valid.");
}
try {
@@ -410,11 +440,10 @@ public boolean doValidate(AbstractMetadata metadata, String lang) {
/**
* Used by the validate embedded service. The validation report is stored in the session.
- *
*/
@Override
public Pair doValidate(UserSession session, String schema, String metadataId, Element md, String lang,
- boolean forEditing) throws Exception {
+ boolean forEditing) throws Exception {
int intMetadataId = Integer.parseInt(metadataId);
String version = null;
LOGGER.debug("Creating validation report for record #{} [schema: {}].", metadataId, schema);
@@ -440,14 +469,14 @@ public Pair doValidate(UserSession session, String schema, Stri
if (xsdErrorCount > 0) {
errorReport.addContent(xsdErrors);
validations.add(new MetadataValidation().setId(new MetadataValidationId(intMetadataId, "xsd"))
- .setStatus(MetadataValidationStatus.INVALID).setRequired(true).setNumTests(xsdErrorCount)
- .setNumFailures(xsdErrorCount));
+ .setStatus(MetadataValidationStatus.INVALID).setRequired(true).setNumTests(xsdErrorCount)
+ .setNumFailures(xsdErrorCount));
if (LOGGER.isDebugEnabled()) {
LOGGER.debug(" - XSD error: {}", Xml.getString(xsdErrors));
}
} else {
validations.add(new MetadataValidation().setId(new MetadataValidationId(intMetadataId, "xsd"))
- .setStatus(MetadataValidationStatus.VALID).setRequired(true).setNumTests(1).setNumFailures(0));
+ .setStatus(MetadataValidationStatus.VALID).setRequired(true).setNumTests(1).setNumFailures(0));
LOGGER.trace("Valid.");
}
@@ -488,19 +517,19 @@ public Pair doValidate(UserSession session, String schema, Stri
/**
* Creates XML schematron report for each set of rules defined in schema directory. This method assumes that you've run enumerateTree on
* the metadata
- *
+ *
* Returns null if no error on validation.
*/
@Override
public Element applyCustomSchematronRules(String schema, int metadataId, Element md, String lang,
- List validations) {
+ List validations) {
return schematronValidator.applyCustomSchematronRules(schema, metadataId, md, lang, validations);
}
/**
* Saves validation status information into the database for the current record.
*
- * @param id the metadata record internal identifier
+ * @param id the metadata record internal identifier
* @param validations the validation reports for each type of validation and schematron validation
*/
private void saveValidationStatus(int id, List validations) {
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java
new file mode 100644
index 00000000000..471ff454938
--- /dev/null
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataIndexer.java
@@ -0,0 +1,77 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
+package org.fao.geonet.kernel.datamanager.draft;
+
+import java.util.Vector;
+
+import org.fao.geonet.constants.Geonet;
+import org.fao.geonet.domain.AbstractMetadata;
+import org.fao.geonet.domain.MetadataDraft;
+import org.fao.geonet.kernel.datamanager.IMetadataIndexer;
+import org.fao.geonet.kernel.datamanager.base.BaseMetadataIndexer;
+import org.fao.geonet.kernel.search.SearchManager;
+import org.fao.geonet.repository.MetadataDraftRepository;
+import org.fao.geonet.utils.Log;
+import org.jdom.Element;
+import org.springframework.beans.factory.annotation.Autowired;
+
+import jeeves.server.context.ServiceContext;
+
+public class DraftMetadataIndexer extends BaseMetadataIndexer implements IMetadataIndexer {
+
+ @Autowired
+ private MetadataDraftRepository metadataDraftRepository;
+
+ @Override
+ public void init(ServiceContext context, Boolean force) throws Exception {
+ super.init(context, force);
+ metadataDraftRepository = context.getBean(MetadataDraftRepository.class);
+ }
+
+ @Override
+ /**
+ * Adds the specific draft related fields.
+ *
+ * @param fullMd
+ * @param moreFields
+ */
+ protected void addExtraFields(AbstractMetadata fullMd, Vector moreFields) {
+ super.addExtraFields(fullMd, moreFields);
+
+ if (fullMd instanceof MetadataDraft) {
+ Log.trace(Geonet.DATA_MANAGER, "We are indexing a draft with uuid " + fullMd.getUuid());
+ moreFields.addElement(SearchManager.makeField(Geonet.IndexFieldNames.DRAFT, "y", true, true));
+ } else {
+ if (metadataDraftRepository.findOneByUuid(fullMd.getUuid()) != null) {
+ Log.trace(Geonet.DATA_MANAGER,
+ "We are indexing a record with a draft associated with uuid " + fullMd.getUuid());
+ moreFields.addElement(SearchManager.makeField(Geonet.IndexFieldNames.DRAFT, "e", true, true));
+ } else {
+ Log.trace(Geonet.DATA_MANAGER,
+ "We are indexing a record with no draft associated with uuid " + fullMd.getUuid());
+ moreFields.addElement(SearchManager.makeField(Geonet.IndexFieldNames.DRAFT, "n", true, true));
+ }
+ }
+ }
+}
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java
new file mode 100644
index 00000000000..41d83ba7456
--- /dev/null
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataManager.java
@@ -0,0 +1,210 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
+package org.fao.geonet.kernel.datamanager.draft;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import javax.annotation.Nonnull;
+import javax.annotation.PostConstruct;
+
+import org.fao.geonet.constants.Geonet;
+import org.fao.geonet.domain.*;
+import org.fao.geonet.kernel.datamanager.IMetadataManager;
+import org.fao.geonet.kernel.datamanager.base.BaseMetadataManager;
+import org.fao.geonet.notifier.MetadataNotifierManager;
+import org.fao.geonet.repository.MetadataDraftRepository;
+import org.fao.geonet.repository.PathSpec;
+import org.fao.geonet.repository.Updater;
+import org.fao.geonet.repository.specification.MetadataSpecs;
+import org.fao.geonet.utils.Log;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.jpa.domain.Specification;
+
+import jeeves.server.context.ServiceContext;
+
+public class DraftMetadataManager extends BaseMetadataManager implements IMetadataManager {
+
+ @Autowired
+ private MetadataDraftRepository metadataDraftRepository;
+
+ /**
+ * To avoid cyclic references on autowired
+ */
+ @PostConstruct
+ @Override
+ public void init() {
+ super.init();
+ }
+
+ public void init(ServiceContext context, Boolean force) throws Exception {
+ metadataDraftRepository = context.getBean(MetadataDraftRepository.class);
+ super.init(context, force);
+ }
+
+
+ /**
+ * Removes a metadata.
+ */
+ @Override
+ public void deleteMetadata(ServiceContext context, String metadataId) throws Exception {
+ AbstractMetadata findOne = metadataUtils.findOne(metadataId);
+
+ if (findOne != null) {
+ boolean isMetadata = findOne.getDataInfo().getType() == MetadataType.METADATA;
+
+
+ if (findOne instanceof Metadata) {
+ // Check if exists draft version and don't allow to remove until draft is removed
+ long countDraft = metadataDraftRepository.count((Specification) MetadataSpecs.hasMetadataUuid(findOne.getUuid()));
+
+ if (countDraft > 0) {
+ throw new Exception("The metadata " + metadataId + " has a draft version. Delete it first to remove the published version.");
+ }
+
+ }
+
+ deleteMetadataFromDB(context, metadataId);
+
+ // Notifies the metadata change to metatada notifier service
+ if (isMetadata) {
+ context.getBean(MetadataNotifierManager.class).deleteMetadata(metadataId, findOne.getUuid(), context);
+ }
+ }
+
+ // --- update search criteria
+ getSearchManager().delete(metadataId + "");
+ // _entityManager.flush();
+ // _entityManager.clear();
+ }
+ /**
+ * For update of owner info.
+ */
+ @Override
+ public synchronized void updateMetadataOwner(final int id, final String owner, final String groupOwner)
+ throws Exception {
+
+ if (metadataDraftRepository.exists(id)) {
+ metadataDraftRepository.update(id, new Updater() {
+ @Override
+ public void apply(@Nonnull MetadataDraft entity) {
+ entity.getSourceInfo().setGroupOwner(Integer.valueOf(groupOwner));
+ entity.getSourceInfo().setOwner(Integer.valueOf(owner));
+ }
+ });
+ } else {
+ super.updateMetadataOwner(id, owner, groupOwner);
+ }
+ }
+
+ @Override
+ public AbstractMetadata save(AbstractMetadata info) {
+ if (info instanceof Metadata) {
+ return super.save((Metadata) info);
+ } else if (info instanceof MetadataDraft) {
+ return metadataDraftRepository.save((MetadataDraft) info);
+ } else {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + info.getClass().getName());
+ }
+ }
+
+ @Override
+ public AbstractMetadata update(int id, @Nonnull Updater extends AbstractMetadata> updater) {
+ AbstractMetadata md = null;
+ Log.trace(Geonet.DATA_MANAGER, "AbstractMetadata.update(" + id + ")");
+ try {
+ Log.trace(Geonet.DATA_MANAGER, "Updating metadata table.");
+ md = super.update(id, updater);
+ } catch (ClassCastException t) {
+ // That's fine, maybe we are on the draft side
+ } catch (Throwable e) {
+ Log.error(Geonet.DATA_MANAGER, e.getMessage(), e);
+ }
+ if (md == null) {
+ try {
+ Log.trace(Geonet.DATA_MANAGER, "Updating draft table.");
+ md = metadataDraftRepository.update(id, (Updater) updater);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + updater.getClass().getName());
+ }
+ }
+ return md;
+ }
+
+ @Override
+ public void deleteAll(Specification extends AbstractMetadata> specs) {
+ try {
+ super.deleteAll(specs);
+ } catch (ClassCastException t) {
+ // That's fine, maybe we are on the draft side
+ }
+ try {
+ metadataDraftRepository.deleteAll((Specification) specs);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + specs.getClass().getName());
+ }
+ }
+
+ @Override
+ public void delete(Integer id) {
+ super.delete(id);
+ if (metadataDraftRepository.exists(id)) {
+ metadataDraftRepository.delete(id);
+ }
+ }
+
+ @Override
+ public void createBatchUpdateQuery(PathSpec extends AbstractMetadata, String> servicesPath, String newUuid,
+ Specification extends AbstractMetadata> harvested) {
+ try {
+ super.createBatchUpdateQuery(servicesPath, newUuid, harvested);
+ } catch (ClassCastException t) {
+ // That's fine, maybe we are on the draft side
+ }
+ try {
+ metadataDraftRepository.createBatchUpdateQuery((PathSpec) servicesPath, newUuid,
+ (Specification) harvested);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + servicesPath.getClass().getName());
+ }
+ }
+
+ @Override
+ public Map findAllSourceInfo(Specification extends AbstractMetadata> specs) {
+ Map res = new HashMap();
+ try {
+ res.putAll(super.findAllSourceInfo(specs));
+ } catch (ClassCastException t) {
+ // That's fine, maybe we are on the draft side
+ }
+ try {
+ res.putAll(metadataDraftRepository.findAllSourceInfo((Specification) specs));
+ } catch (ClassCastException t) {
+ // That's fine, maybe we are on the metadata side
+ }
+
+ return res;
+ }
+
+}
diff --git a/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java
new file mode 100644
index 00000000000..61aa77ce60f
--- /dev/null
+++ b/core/src/main/java/org/fao/geonet/kernel/datamanager/draft/DraftMetadataUtils.java
@@ -0,0 +1,640 @@
+//=============================================================================
+//=== Copyright (C) 2001-2011 Food and Agriculture Organization of the
+//=== United Nations (FAO-UN), United Nations World Food Programme (WFP)
+//=== and United Nations Environment Programme (UNEP)
+//===
+//=== This program is free software; you can redistribute it and/or modify
+//=== it under the terms of the GNU General Public License as published by
+//=== the Free Software Foundation; either version 2 of the License, or (at
+//=== your option) any later version.
+//===
+//=== This program is distributed in the hope that it will be useful, but
+//=== WITHOUT ANY WARRANTY; without even the implied warranty of
+//=== MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+//=== General Public License for more details.
+//===
+//=== You should have received a copy of the GNU General Public License
+//=== along with this program; if not, write to the Free Software
+//=== Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//===
+//=== Contact: Jeroen Ticheler - FAO - Viale delle Terme di Caracalla 2,
+//=== Rome - Italy. email: geonetwork@osgeo.org
+//==============================================================================
+
+package org.fao.geonet.kernel.datamanager.draft;
+
+import static org.fao.geonet.repository.specification.MetadataSpecs.hasMetadataUuid;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Consumer;
+
+import javax.annotation.Nonnull;
+import javax.persistence.EntityNotFoundException;
+
+import org.apache.commons.io.FileUtils;
+import org.eclipse.jetty.io.RuntimeIOException;
+import org.fao.geonet.constants.Geonet;
+import org.fao.geonet.domain.AbstractMetadata;
+import org.fao.geonet.domain.Group;
+import org.fao.geonet.domain.ISODate;
+import org.fao.geonet.domain.Metadata;
+import org.fao.geonet.domain.MetadataCategory;
+import org.fao.geonet.domain.MetadataDataInfo;
+import org.fao.geonet.domain.MetadataDraft;
+import org.fao.geonet.domain.MetadataFileUpload;
+import org.fao.geonet.domain.MetadataHarvestInfo;
+import org.fao.geonet.domain.MetadataSourceInfo;
+import org.fao.geonet.domain.MetadataStatus;
+import org.fao.geonet.domain.MetadataStatusId;
+import org.fao.geonet.domain.MetadataType;
+import org.fao.geonet.domain.OperationAllowed;
+import org.fao.geonet.domain.Pair;
+import org.fao.geonet.domain.ReservedOperation;
+import org.fao.geonet.domain.StatusValue;
+import org.fao.geonet.kernel.AccessManager;
+import org.fao.geonet.kernel.UpdateDatestamp;
+import org.fao.geonet.kernel.datamanager.IMetadataManager;
+import org.fao.geonet.kernel.datamanager.IMetadataOperations;
+import org.fao.geonet.kernel.datamanager.IMetadataStatus;
+import org.fao.geonet.kernel.datamanager.base.BaseMetadataUtils;
+import org.fao.geonet.kernel.metadata.StatusActions;
+import org.fao.geonet.kernel.metadata.StatusActionsFactory;
+import org.fao.geonet.lib.Lib;
+import org.fao.geonet.repository.GroupRepository;
+import org.fao.geonet.repository.MetadataDraftRepository;
+import org.fao.geonet.repository.MetadataFileUploadRepository;
+import org.fao.geonet.repository.SimpleMetadata;
+import org.fao.geonet.repository.StatusValueRepository;
+import org.fao.geonet.repository.Updater;
+import org.fao.geonet.repository.specification.MetadataFileUploadSpecs;
+import org.fao.geonet.utils.Log;
+import org.fao.geonet.utils.Xml;
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Page;
+import org.springframework.data.domain.PageImpl;
+import org.springframework.data.domain.Pageable;
+import org.springframework.data.jpa.domain.Specification;
+
+import com.google.common.base.Optional;
+
+import jeeves.server.context.ServiceContext;
+
+public class DraftMetadataUtils extends BaseMetadataUtils {
+
+ @Autowired
+ private MetadataDraftRepository metadataDraftRepository;
+ @Autowired
+ private IMetadataOperations metadataOperations;
+ @Autowired
+ private IMetadataStatus metadataStatus;
+ @Autowired
+ private GroupRepository groupRepository;
+ @Autowired
+ private StatusValueRepository statusValueRepository;
+ @Autowired
+ private AccessManager am;
+
+ private ServiceContext context;
+
+ public void init(ServiceContext context, Boolean force) throws Exception {
+ this.metadataDraftRepository = context.getBean(MetadataDraftRepository.class);
+ this.metadataOperations = context.getBean(IMetadataOperations.class);
+ this.metadataStatus = context.getBean(IMetadataStatus.class);
+ this.groupRepository = context.getBean(GroupRepository.class);
+ this.statusValueRepository = context.getBean(StatusValueRepository.class);
+ this.am = context.getBean(AccessManager.class);
+ this.context = context;
+ super.init(context, force);
+ }
+
+ @Override
+ public void setTemplateExt(final int id, final MetadataType metadataType) throws Exception {
+ if (metadataDraftRepository.exists(id)) {
+ metadataDraftRepository.update(id, new Updater() {
+ @Override
+ public void apply(@Nonnull MetadataDraft metadata) {
+ final MetadataDataInfo dataInfo = metadata.getDataInfo();
+ dataInfo.setType(metadataType);
+ }
+ });
+ } else {
+ super.setTemplateExt(id, metadataType);
+ }
+ }
+
+ /**
+ * Set metadata type to subtemplate and set the title. Only subtemplates need to
+ * persist the title as it is used to give a meaningful title for use when
+ * offering the subtemplate to users in the editor.
+ *
+ * @param id
+ * Metadata id to set to type subtemplate
+ * @param title
+ * Title of metadata of subtemplate/fragment
+ */
+ @Override
+ public void setSubtemplateTypeAndTitleExt(final int id, String title) throws Exception {
+ if (metadataDraftRepository.exists(id)) {
+ metadataDraftRepository.update(id, new Updater() {
+ @Override
+ public void apply(@Nonnull MetadataDraft metadata) {
+ final MetadataDataInfo dataInfo = metadata.getDataInfo();
+ dataInfo.setType(MetadataType.SUB_TEMPLATE);
+ if (title != null) {
+ dataInfo.setTitle(title);
+ }
+ }
+ });
+
+ } else {
+ super.setSubtemplateTypeAndTitleExt(id, title);
+ }
+ }
+
+ @Override
+ public void setHarvestedExt(final int id, final String harvestUuid, final Optional harvestUri)
+ throws Exception {
+ if (metadataDraftRepository.exists(id)) {
+ metadataDraftRepository.update(id, new Updater() {
+ @Override
+ public void apply(MetadataDraft metadata) {
+ MetadataHarvestInfo harvestInfo = metadata.getHarvestInfo();
+ harvestInfo.setUuid(harvestUuid);
+ harvestInfo.setHarvested(harvestUuid != null);
+ harvestInfo.setUri(harvestUri.orNull());
+ }
+ });
+ } else {
+ super.setHarvestedExt(id, harvestUuid, harvestUri);
+ }
+ }
+
+ /**
+ * @param id
+ * @param displayOrder
+ * @throws Exception
+ */
+ @Override
+ public void updateDisplayOrder(final String idString, final String displayOrder) throws Exception {
+ Integer id = Integer.valueOf(idString);
+ if (metadataDraftRepository.exists(id)) {
+ metadataDraftRepository.update(id, new Updater() {
+ @Override
+ public void apply(MetadataDraft entity) {
+ entity.getDataInfo().setDisplayOrder(Integer.parseInt(displayOrder));
+ }
+ });
+ } else {
+ super.updateDisplayOrder(idString, displayOrder);
+ }
+ }
+
+ /**
+ * Rates a metadata.
+ *
+ * @param ipAddress
+ * ipAddress IP address of the submitting client
+ * @param rating
+ * range should be 1..5
+ * @throws Exception
+ * hmm
+ */
+ @Override
+ public int rateMetadata(final int metadataId, final String ipAddress, final int rating) throws Exception {
+ final int newRating = ratingByIpRepository.averageRating(metadataId);
+
+ if (metadataDraftRepository.exists(metadataId)) {
+ metadataDraftRepository.update(metadataId, new Updater() {
+ @Override
+ public void apply(MetadataDraft entity) {
+ entity.getDataInfo().setRating(newRating);
+ }
+ });
+ } else {
+ return super.rateMetadata(metadataId, ipAddress, rating);
+ }
+ return rating;
+ }
+
+ @SuppressWarnings("unchecked")
+ @Override
+ public long count(Specification extends AbstractMetadata> specs) {
+ long tmp = 0;
+ try {
+ tmp += super.count((Specification) specs);
+ } catch (ClassCastException t) {
+ // Maybe it is not a Specification
+ }
+ try {
+ tmp += metadataDraftRepository.count((Specification) specs);
+ } catch (ClassCastException t) {
+ // Maybe it is not a Specification
+ }
+ return tmp;
+ }
+
+ @Override
+ public long count() {
+ return super.count() + metadataDraftRepository.count();
+ }
+
+ @Override
+ public AbstractMetadata findOne(int id) {
+ if (super.exists(id)) {
+ return super.findOne(id);
+ }
+ return metadataDraftRepository.findOne(id);
+ }
+
+ @Override
+ public boolean existsMetadataUuid(String uuid) throws Exception {
+ return super.existsMetadataUuid(uuid) || !findAllIdsBy(hasMetadataUuid(uuid)).isEmpty();
+ }
+
+ /**
+ * If the user has permission to see the draft, draft goes first
+ */
+ @Override
+ public AbstractMetadata findOneByUuid(String uuid) {
+ AbstractMetadata md = super.findOneByUuid(uuid);
+ try {
+ if (md != null && am.canEdit(context, Integer.toString(md.getId()))) {
+ AbstractMetadata tmp = metadataDraftRepository.findOneByUuid(uuid);
+ if (tmp != null) {
+ md = tmp;
+ }
+ } else if (md == null) {
+ // A draft without an approved md
+ md = metadataDraftRepository.findOneByUuid(uuid);
+ }
+ } catch (Exception e) {
+ Log.error(Geonet.DATA_MANAGER, e, e);
+ }
+ return md;
+ }
+
+ /**
+ * Return all records, including drafts.
+ */
+ @Override
+ public List extends AbstractMetadata> findAllByUuid(String uuid) {
+ List res = new LinkedList();
+ res.addAll(super.findAllByUuid(uuid));
+ res.addAll(metadataDraftRepository.findAllByUuid(uuid));
+ return res;
+ }
+
+ @Override
+ public AbstractMetadata findOne(Specification extends AbstractMetadata> spec) {
+ AbstractMetadata md = null;
+
+ try {
+ md = super.findOne(spec);
+ } catch (ClassCastException t) {
+ // That's fine, it can be a draft specification
+ }
+
+ if (md == null) {
+ try {
+ md = metadataDraftRepository.findOne((Specification) spec);
+ } catch (ClassCastException t) {
+ throw new ClassCastException("Unknown AbstractMetadata subtype: " + spec.getClass().getName());
+ }
+ }
+
+ return md;
+ }
+
+ @Override
+ public AbstractMetadata findOne(String id) {
+ AbstractMetadata md = super.findOne(id);
+ if (md == null) {
+ md = metadataDraftRepository.findOne(id);
+ }
+ return md;
+ }
+
+ @Override
+ public List extends AbstractMetadata> findAllByHarvestInfo_Uuid(String uuid) {
+ List list = new LinkedList();
+ list.addAll(metadataDraftRepository.findAllByHarvestInfo_Uuid(uuid));
+ list.addAll(super.findAllByHarvestInfo_Uuid(uuid));
+ return list;
+ }
+
+ @Override
+ public Iterable extends AbstractMetadata> findAll(Set keySet) {
+ List list = new LinkedList();
+ for (AbstractMetadata md : super.findAll(keySet)) {
+ list.add(md);
+ }
+ list.addAll(metadataDraftRepository.findAll(keySet));
+ return list;
+ }
+
+ @Override
+ public List extends AbstractMetadata> findAll(Specification extends AbstractMetadata> specs) {
+ List list = new LinkedList();
+ try {
+ list.addAll(super.findAll(specs));
+ } catch (ClassCastException t) {
+ // That's fine, maybe it is a draft specification
+ }
+ try {
+ list.addAll(metadataDraftRepository.findAll((Specification) specs));
+ } catch (ClassCastException t) {
+ // That's fine, maybe it is a metadata specification
+ }
+ return list;
+ }
+
+ @Override
+ public List findAllSimple(String harvestUuid) {
+ List