/* See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Esri Inc. licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.esri.gpt.control.publication; import com.esri.gpt.catalog.arcgis.metadata.AGSProcessorConfig; import com.esri.gpt.catalog.harvest.jobs.HjRecord; import com.esri.gpt.catalog.harvest.repository.HrCriteria; import com.esri.gpt.catalog.harvest.repository.HrHarvestRequest; import com.esri.gpt.catalog.harvest.repository.HrResult; import com.esri.gpt.catalog.management.CollectionDao; import com.esri.gpt.catalog.management.MmdActionCriteria; import com.esri.gpt.catalog.management.MmdActionRequest; import com.esri.gpt.catalog.management.MmdActionResult; import com.esri.gpt.catalog.management.MmdCriteria; import com.esri.gpt.catalog.management.MmdQueryCriteria; import com.esri.gpt.catalog.management.MmdQueryRequest; import com.esri.gpt.catalog.management.MmdQueryResult; import com.esri.gpt.catalog.management.MmdRecord; import com.esri.gpt.catalog.management.MmdResult; import com.esri.gpt.control.view.PageCursorPanel; import com.esri.gpt.control.view.SelectablePublishers; import com.esri.gpt.control.webharvest.protocol.ProtocolFactories; import com.esri.gpt.control.webharvest.protocol.ProtocolFactory; import com.esri.gpt.control.webharvest.protocol.factories.AgpProtocolFactory; import com.esri.gpt.framework.collection.StringAttributeMap; import com.esri.gpt.framework.collection.StringSet; import com.esri.gpt.framework.context.ApplicationConfiguration; import com.esri.gpt.framework.context.ApplicationContext; import com.esri.gpt.framework.context.RequestContext; import com.esri.gpt.framework.jsf.BaseActionListener; import com.esri.gpt.framework.jsf.MessageBroker; import com.esri.gpt.framework.security.identity.NotAuthorizedException; import com.esri.gpt.framework.security.identity.local.SimpleIdentityAdapter; import com.esri.gpt.framework.security.metadata.MetadataAccessPolicy; import com.esri.gpt.framework.security.principal.Publisher; import com.esri.gpt.framework.util.Val; import java.util.ArrayList; import javax.faces.component.UIComponent; import javax.faces.event.AbortProcessingException; import javax.faces.event.ActionEvent; import javax.faces.model.SelectItem; /** * Handles actions related to metadata management. */ public class ManageMetadataController extends BaseActionListener { // class variables ============================================================= // instance variables ========================================================== private MmdCriteria _criteria; private PageCursorPanel _pageCursorPanel; private MmdResult _result; private SelectableCollections _selectableCollections; private SelectablePublishers _selectablePublishers; private SelectableGroups _candidateGroups; private MetadataAccessPolicy _metadataAccessPolicyConfig; private MmdQueryCriteria _queryCriteriaForAction = new MmdQueryCriteria(); private boolean _useCollections = false; // constructors ================================================================ /** Default constructor. */ public ManageMetadataController() { super(); setResult(new MmdResult()); // initialize the selectablables _selectablePublishers = new SelectablePublishers(); _candidateGroups = new SelectableGroups(); _selectableCollections = new SelectableCollections(); // initialize the page cursor panel String sExpression = "#{ManageMetadataController.processAction}"; _pageCursorPanel = new PageCursorPanel(); _pageCursorPanel.setActionListenerExpression(sExpression); _pageCursorPanel.setPageCursor(getQueryResult().getPageCursor()); } // properties ================================================================== /** * Gets list of candidate groups * @return the list of candidate groups */ public SelectableGroups getCandidateGroups() { return _candidateGroups; } /** * Sets list of candidate groups * @param candidateGroups the list of candidate groups */ public void setCandidateGroups(SelectableGroups candidateGroups) { this._candidateGroups = candidateGroups; } /** * Gets access policy configuration * @return access policy configuration */ public MetadataAccessPolicy getMetadataAccessPolicyConfig() { return _metadataAccessPolicyConfig; } /** * Sets access policy configuration. * @param metadataAccessPolicyConfig access policy configuration */ public void setAccessPolicyConfig( MetadataAccessPolicy metadataAccessPolicyConfig) { this._metadataAccessPolicyConfig = metadataAccessPolicyConfig; } /** * Gets the action criteria. * @return the action criteria */ public MmdActionCriteria getActionCriteria() { return getCriteria().getActionCriteria(); } /** * Gets the action result. * @return the action result */ private MmdActionResult getActionResult() { return getResult().getActionResult(); } /** * Determine if apply to all is allowable. * @return <code>true</code> if apply to all is allowable */ public boolean getAllowApplyToAll() { RequestContext context = this.getContextBroker().extractRequestContext(); StringAttributeMap params = context.getCatalogConfiguration().getParameters(); String s = Val.chkStr(params.getValue("catalog.admin.allowApplyToAll")); return !s.equalsIgnoreCase("false"); } /** * Returns a false condition in support of the check-all control on the manage metadata page. * @return false */ public boolean getAlwaysFalse() { return false; } /** * Accepts a boolean in support of the check-all control on the manage metadata page. * @param ignored this value is ignored (the state of this control is not preserved) */ public void setAlwaysFalse(boolean ignored) { } /** * Gets the criteria for a manage metadata request. * @return the criteria */ public MmdCriteria getCriteria() { return _criteria; } /** * Sets the criteria for a manage metadata request. * @param criteria the criteria */ public void setCriteria(MmdCriteria criteria) { _criteria = criteria; } /** * Gets the panel for displaying the page cursor. * @return the page cursor panel */ public PageCursorPanel getPageCursorPanel() { return _pageCursorPanel; } /** * Gets the query criteria. * @return the query criteria */ public MmdQueryCriteria getQueryCriteria() { return getCriteria().getQueryCriteria(); } /** * Gets the query result. * @return the query result */ public MmdQueryResult getQueryResult() { return getResult().getQueryResult(); } /** * Gets the maximum number of records to be displayed per page. * @return the maximum number of records per page */ public int getRecordsPerPage() { return getQueryResult().getPageCursor().getRecordsPerPage(); } /** * Sets the maximum number of records to be displayed per page. * @param recordsPerPage the maximum number of records per page */ public void setRecordsPerPage(int recordsPerPage) { getQueryResult().getPageCursor().setRecordsPerPage(recordsPerPage); } /** * Gets the result of a manage metadata request. * @return the result */ private MmdResult getResult() { return _result; } /** * Sets the result of a manage metadata request. * @param result the result */ private void setResult(MmdResult result) { _result = result; } /** * Gets list of selectable collections. * @return the list of selectable collections */ public SelectableCollections getSelectableCollections() { return _selectableCollections; } /** * Gets list of selectable publishers. * @return the list of selectable publishers */ public SelectablePublishers getSelectablePublishers() { return _selectablePublishers; } /** * Determine if collections are in use. * @return <code>true</code> if collections are in use */ public boolean getUseCollections() { RequestContext context = this.getContextBroker().extractRequestContext(); CollectionDao colDao = new CollectionDao(context); return colDao.getUseCollections(); } /** * Check if document access policy type is unrestricted * @return <code>true</code> if policy is unrestricted */ public boolean isPolicyUnrestricted() { if(getCriteria().getActionCriteria().getMetadataAccessPolicyType() != null){ return getCriteria().getActionCriteria().getMetadataAccessPolicyType() .equalsIgnoreCase(MetadataAccessPolicy.TYPE_UNRESTRICTED); } return false; } // methods ===================================================================== /** * Executes an action against a set of metadata records. * @param event the associated JSF action event * @param context the context associated with the active request * @param actionCriteria the criteria for the action * @param publisher the publisher * @param applyToAll <code>true</code> to apply action to current set * @throws Exception if an exception occurs */ private void executeAction(ActionEvent event, final RequestContext context, MmdActionCriteria actionCriteria, Publisher publisher, boolean applyToAll) throws Exception { MessageBroker msgBroker = extractMessageBroker(); // check to ensure that records were selected if (actionCriteria.getSelectedRecordIdSet().size() == 0 && applyToAll==false) { msgBroker.addErrorMessage("catalog.publication.manageMetadata.action.err.noneSelected"); } else { // check the publisher Publisher publisherForAction = publisher; if (!publisher.getIsAdministrator()) { String sOwner = getQueryCriteria().getOwner(); if (sOwner.length() == 0) { sOwner = publisher.getKey(); } if (!sOwner.equalsIgnoreCase(publisher.getKey())) { if (!Publisher.buildSelectablePublishers(context, true).containsKey(sOwner)) { throw new NotAuthorizedException("Not authorized."); } else { publisherForAction = new Publisher(context, sOwner); } } } // execute the request MmdCriteria criteria = new MmdCriteria(); criteria.setActionCriteria(actionCriteria); if (_metadataAccessPolicyConfig==null) { getSelectablePublishers().build(context, true); prepareAccessPolicyConfig(context); prepareGroups(context); prepareActionCriteria(context); } String defaultGroup = _metadataAccessPolicyConfig.getAccessToGroupDN(); if (defaultGroup != null && defaultGroup.trim().length() > 0) { ArrayList<String> defaultAcl = new ArrayList<String>(); defaultAcl.add(getActionCriteria().getToggleMetadataAccessPolicy()); criteria.getActionCriteria().setMetadataAccessPolicy(defaultAcl); } MmdActionRequest request = new MmdActionRequest(context,publisherForAction,criteria,getResult()); if (!applyToAll) { request.execute(); } else { if (!_queryCriteriaForAction.getIsEmpty()) { request.execute(_queryCriteriaForAction); } } // set the success message int nModified = getActionResult().getNumberOfRecordsModified(); if (nModified > 0) { String sKey = "catalog.publication.manageMetadata.action.success"; if (actionCriteria.getActionKey().equalsIgnoreCase("delete")) { sKey += ".delete"; } String[] args = new String[1]; args[0] = "" + nModified; msgBroker.addSuccessMessage(sKey, args); } if (request.hadUnalteredDraftDocuments()) { msgBroker.addErrorMessage("catalog.publication.manageMetadata.action.err.draftUnaltered"); } } } /** * Executes a search for metadata records. * @param event the associated JSF action event * @param context the context associated with the active request * @param publisher the publisher * @throws Exception if an exception occurs */ private void executeSearch(ActionEvent event, RequestContext context, Publisher publisher) throws Exception { MessageBroker msgBroker = extractMessageBroker(); // check the publisher if (!publisher.getIsAdministrator()) { if (getQueryCriteria().getOwner().length() == 0) { getQueryCriteria().setOwner(publisher.getKey()); } String sOwner = getQueryCriteria().getOwner(); if (!sOwner.equalsIgnoreCase(publisher.getKey())) { if (!Publisher.buildSelectablePublishers(context, true).containsKey(sOwner)) { getQueryCriteria().setOwner(publisher.getKey()); } } } // execute the request MmdQueryRequest request; request = new MmdQueryRequest(context, publisher, getCriteria(), getResult()); request.execute(); // determine if collections are in use CollectionDao colDao = new CollectionDao(context); boolean useCollections = colDao.getUseCollections(); // set the resource messages for the results String sMsg; String sValue; for (MmdRecord record : request.getQueryResult().getRecords()) { // lookup approval status sValue = record.getApprovalStatus(); sMsg = msgBroker.retrieveMessage("catalog.publication.manageMetadata.status."+sValue); record.setApprovalStatusMsg(sMsg); // lookup publication method sValue = record.getPublicationMethod(); sMsg = msgBroker.retrieveMessage("catalog.publication.manageMetadata.method."+sValue); record.setPublicationMethodMsg(sMsg); // collection membership if (useCollections) { sValue = Val.chkStr(record.getCollectionMembership()); if (sValue.length() > 0) { Object[] p = new String[]{sValue}; sMsg = msgBroker.retrieveMessage("catalog.publication.manageMetadata.sharing.collection.popup",p); record.setCollectionMembership(sMsg); } } } } /** * Executes synchronization. * @param event the associated JSF action event * @param context the context associated with the active request * @param actionCriteria the criteria for the action * @throws Exception if an exception occurs */ private void executeSynchronization(ActionEvent event, RequestContext context, MmdActionCriteria actionCriteria) throws Exception { StringSet uuids = actionCriteria.getSelectedRecordIdSet(); String[] aUuids = uuids.toArray(new String[uuids.size()]); HrHarvestRequest hrvFullRequest = new HrHarvestRequest(context,aUuids,HjRecord.JobType.Now,new HrCriteria(),new HrResult()); hrvFullRequest.execute(); if (hrvFullRequest.getActionResult().getNumberOfRecordsModified() > 0) { extractMessageBroker().addSuccessMessage( "catalog.harvest.manage.message.synchronized", new Object[]{Integer.toString(hrvFullRequest.getActionResult(). getNumberOfRecordsModified()) }); } else { extractMessageBroker().addSuccessMessage( "catalog.harvest.manage.message.synchronized.none"); } } /** * Executes canceling of the synchronization. * @param event the associated JSF action event * @param context the context associated with the active request * @param actionCriteria the criteria for the action * @throws Exception if an exception occurs */ private void executeCancelSynchronization(ActionEvent event, RequestContext context, MmdActionCriteria actionCriteria) throws Exception { StringSet uuids = actionCriteria.getSelectedRecordIdSet(); String[] aUuids = uuids.toArray(new String[uuids.size()]); int canceledCount = 0; for (String uuid : aUuids) { if (context.getApplicationContext().getHarvestingEngine().cancel(context, uuid)) { canceledCount++; } } extractMessageBroker().addSuccessMessage( "catalog.harvest.manage.message.canceled", new Object[]{Integer.toString(canceledCount)}); } /** * Executes canceling of the synchronization. * @param event the associated JSF action event * @param context the context associated with the active request * @param actionCriteria the criteria for the action * @throws Exception if an exception occurs */ private void executeShowHarvested(ActionEvent event, RequestContext context, MmdActionCriteria actionCriteria) throws Exception { StringSet uuids = actionCriteria.getSelectedRecordIdSet(); String[] aUuids = uuids.toArray(new String[uuids.size()]); if (aUuids.length>0) { getCriteria().getQueryCriteria().reset(); getCriteria().getQueryCriteria().setSiteUuid(aUuids[0]); } } /** * Executes canceling of the synchronization. * @param event the associated JSF action event * @param context the context associated with the active request * @param actionCriteria the criteria for the action * @throws Exception if an exception occurs */ private void executeFind(ActionEvent event, RequestContext context, MmdActionCriteria actionCriteria) throws Exception { StringSet uuids = actionCriteria.getSelectedRecordIdSet(); String[] aUuids = uuids.toArray(new String[uuids.size()]); if (aUuids.length>0) { getCriteria().getQueryCriteria().reset(); getCriteria().getQueryCriteria().setUuid(aUuids[0]); } } /** * Fired when the getPrepareView() property is accessed. * <br/>This event is triggered from the page during the * render response phase of the JSF cycle. * <p> * The UI components associated with the PageCursorPanel are * build on the firing of this event. * @param context the context associated with the active request * @throws Exception if an exception occurs */ @Override protected void onPrepareView(final RequestContext context) throws Exception { CollectionDao colDao = new CollectionDao(context); this._useCollections = colDao.getUseCollections(); if (this._useCollections) { this.prepareCollections(context); } // build the selectable list of publishers getSelectablePublishers().build(context,true); prepareAccessPolicyConfig(context); prepareGroups(context); prepareActionCriteria(context); // build the UI components associated with the PageCursorPanel getPageCursorPanel().setPageCursor(getQueryResult().getPageCursor()); } private void prepareAccessPolicyConfig(RequestContext context) throws Exception { _metadataAccessPolicyConfig = context.getApplicationConfiguration().getMetadataAccessPolicy(); if(context.newIdentityAdapter() instanceof SimpleIdentityAdapter){ if(_metadataAccessPolicyConfig.getAccessPolicyType().equals(MetadataAccessPolicy.TYPE_RESTRICTED)){ _metadataAccessPolicyConfig.setAccessPolicyType(MetadataAccessPolicy.TYPE_PUBLIC_PROTECTED); _metadataAccessPolicyConfig.setAccessToGroupDN("protected"); } } } private void prepareCollections(RequestContext context) throws Exception { if (false) return; this.getSelectableCollections().buildAll(context); } private void prepareGroups(RequestContext context) throws Exception { if (_metadataAccessPolicyConfig==null) { prepareAccessPolicyConfig(context); } String defaultGroup = _metadataAccessPolicyConfig.getAccessToGroupDN(); if (defaultGroup == null || defaultGroup.trim().length() == 0) { // build the candidate list of access groups getCandidateGroups().buildAllGroups(context); } } private void prepareActionCriteria(RequestContext context) throws Exception { if (_metadataAccessPolicyConfig==null) { prepareAccessPolicyConfig(context); } getActionCriteria().setMetadataAccessPolicyType(_metadataAccessPolicyConfig.getAccessPolicyType()); getActionCriteria().setAccessToGroupDN(_metadataAccessPolicyConfig.getAccessToGroupDN()); } /** * Checks if is there any selectable group * @return <code>true</code> if is there at leas one selectable group present */ public boolean isSelectableGroups(){ return _candidateGroups.getSize()>0?true:false; } /** * Gets query criteria as encrypted string. * Gets data from the last search criteria invoked. * @return query criteria as encrypted string */ public String getQueryCriteriaAsEncrypedString() { // get directly from the current query criteria return getQueryCriteria().getContentAsEncryptedString(); } /** * Sets query criteria as encrypted string. * Instead overwriting query criteria for search, stores data in a separate * object. * @param content query criteria as encrypted string */ public void setQueryCriteriaAsEncrypedString(String content) { // don't update current criteria; instead store in a designated field _queryCriteriaForAction.setContentAsEncryptedString(content); } /** * Gets protocols eligible to choose. * @return collection of protocols eligible to choose */ public ArrayList<SelectItem> getProtocols() { ArrayList<SelectItem> protocols = new ArrayList<SelectItem>(); MessageBroker msgBroker = getContextBroker().extractMessageBroker(); ApplicationContext appCtx = ApplicationContext.getInstance(); ApplicationConfiguration appCfg = appCtx.getConfiguration(); ProtocolFactories protocolFactories = appCfg.getProtocolFactories(); protocols.add(new SelectItem("", msgBroker.retrieveMessage("catalog.harvest.manage.edit.protocol.any"))); for (String key: protocolFactories.getKeys()) { ProtocolFactory pf = protocolFactories.get(key); if (pf instanceof AgpProtocolFactory && !AGSProcessorConfig.isAvailable()) continue; String resourceKey = protocolFactories.getResourceKey(key); SelectItem item = new SelectItem(key.toLowerCase(), msgBroker.retrieveMessage(resourceKey)); protocols.add(item); } return protocols; } /** * Handles a metadata management action. * <br/>This is the default entry point for a sub-class of BaseActionListener. * <br/>This BaseActionListener handles the JSF processAction method and * invokes the processSubAction method of the sub-class. * @param event the associated JSF action event * @param context the context associated with the active request * @throws AbortProcessingException if processing should be aborted * @throws Exception if an exception occurs */ @Override protected void processSubAction(ActionEvent event, RequestContext context) throws AbortProcessingException, Exception { // duplicate the action criteria for the request to limit // thread safety issues MmdActionCriteria actionCriteria; actionCriteria = new MmdActionCriteria(getActionCriteria()); // check for a page cursor navigation event getPageCursorPanel().checkActionEvent(event, true); // prepare the publisher Publisher publisher = new Publisher(context); // determine and execute the command UIComponent component = event.getComponent(); String sCommand = Val.chkStr((String) component.getAttributes().get("command")); if (sCommand.equals("")) { // set the sort option } else if (sCommand.equals("sort")) { String sCol = (String) component.getAttributes().get("column"); String sDir = (String) component.getAttributes().get("defaultDirection"); getQueryCriteria().getSortOption().setColumnKey(sCol, true, sDir); // execute an action } else if (sCommand.equals("executeAction")) { String sAction = actionCriteria.getActionKey(); boolean applyToAll = Val.chkBool((String) component.getAttributes().get("applyToAll"), false); boolean bRequiresAdmin = sAction.equalsIgnoreCase("transfer") || sAction.equalsIgnoreCase("setApproved") || sAction.equalsIgnoreCase("setDisapproved") || sAction.equalsIgnoreCase("setReviewed") || applyToAll; if (bRequiresAdmin && !publisher.getIsAdministrator()) { throw new NotAuthorizedException("Not authorized."); } executeAction(event, context, actionCriteria, publisher, applyToAll); } else if (sCommand.equals("synchronize")) { executeSynchronization(event, context, actionCriteria); } else if (sCommand.equals("cancel")) { executeCancelSynchronization(event, context, actionCriteria); } else if (sCommand.equals("showharvested")) { executeShowHarvested(event, context, actionCriteria); } else if (sCommand.equals("find")) { executeFind(event, context, actionCriteria); } // always execute the search for metadata records executeSearch(event, context, publisher); } }