/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2011-2015 ForgeRock AS. All rights reserved.
*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the License at
* http://forgerock.org/license/CDDLv1.0.html
* See the License for the specific language governing
* permission and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at http://forgerock.org/license/CDDLv1.0.html
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* $Id$
*/
package org.forgerock.openidm.provisioner.openicf.impl;
import org.forgerock.json.JsonValue;
import org.forgerock.json.resource.ForbiddenException;
import org.forgerock.json.resource.ResourceResponse;
import org.forgerock.json.resource.ResourceException;
import org.forgerock.openidm.crypto.CryptoService;
import org.forgerock.openidm.provisioner.Id;
import org.forgerock.openidm.provisioner.openicf.OperationHelper;
import org.forgerock.openidm.provisioner.openicf.commons.ObjectClassInfoHelper;
import org.forgerock.openidm.provisioner.openicf.commons.OperationOptionInfoHelper;
import org.identityconnectors.common.Assertions;
import org.identityconnectors.framework.api.operations.APIOperation;
import org.identityconnectors.framework.common.objects.*;
import java.lang.reflect.UndeclaredThrowableException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
/**
* @version $Revision$ $Date$
*/
public class OperationHelperImpl implements OperationHelper {
private final ObjectClassInfoHelper objectClassInfoHelper;
private final Map<Class<? extends APIOperation>, OperationOptionInfoHelper> operations;
private final List<Map<String, Object>> resultList = new ArrayList<Map<String, Object>>();
private final Id systemObjectSetId;
private final CryptoService cryptoService;
/**
* @param systemObjectSetId
* @param objectClassInfoHelper
* @param connectorObjectOptions
* @param cryptoService
* @throws NullPointerException if any of the input values is null.
*/
public OperationHelperImpl(Id systemObjectSetId, ObjectClassInfoHelper objectClassInfoHelper,
Map<Class<? extends APIOperation>, OperationOptionInfoHelper> connectorObjectOptions,
CryptoService cryptoService) {
this.objectClassInfoHelper = Assertions.nullChecked(objectClassInfoHelper, "objectClassInfoHelper");
this.operations = Assertions.nullChecked(connectorObjectOptions, "connectorObjectOptions");
this.systemObjectSetId = Assertions.nullChecked(systemObjectSetId, "systemObjectSetId");
this.cryptoService = cryptoService;
}
public boolean isOperationPermitted(Class<? extends APIOperation> operation) throws ResourceException {
OperationOptionInfoHelper operationOptionInfoHelper = operations.get(operation);
String reason = "not supported.";
if (null != operationOptionInfoHelper
&& (null == operationOptionInfoHelper.getSupportedObjectTypes()
|| operationOptionInfoHelper.getSupportedObjectTypes().contains(
objectClassInfoHelper.getObjectClass().getObjectClassValue()))) {
if (!operationOptionInfoHelper.isDenied()) {
return true;
} else if (OperationOptionInfoHelper.OnActionPolicy.ALLOW.equals(operationOptionInfoHelper.getOnActionPolicy())) {
return false;
}
reason = "denied.";
}
throw new ForbiddenException("Operation " + operation.getCanonicalName() + " is " + reason);
}
public OperationOptionsBuilder getOperationOptionsBuilder(Class<? extends APIOperation> operation, ConnectorObject connectorObject, JsonValue source) throws Exception {
return operations.get(operation).build(source, objectClassInfoHelper);
}
public ObjectClass getObjectClass() {
return objectClassInfoHelper.getObjectClass();
}
/*
public Filter build(Map<String, Object> query, Map<String, Object> params) throws Exception {
Operator operator = createOperator(query, params);
return operator.createFilter();
}
*/
public ConnectorObject build(Class<? extends APIOperation> operation, JsonValue source) throws Exception {
return objectClassInfoHelper.build(operation, null, source, cryptoService);
}
/*
public ConnectorObject build(Class<? extends APIOperation> operation, String id, JsonValue source) throws Exception {
//TODO do something with ID
return objectClassInfoHelper.build(operation, id, source, cryptoService);
}
*/
public JsonValue build(ConnectorObject source) throws Exception {
JsonValue result = objectClassInfoHelper.build(source, cryptoService).getContent();
resetUid(source.getUid(), result);
if (null != source.getUid().getRevision()) {
//System supports Revision
result.put(ResourceResponse.FIELD_CONTENT_REVISION, source.getUid().getRevision());
}
return result;
}
public void resetUid(Uid uid, JsonValue target) {
if (null != uid && null != target) {
// TODO are we going to encode ids?
target.put(ResourceResponse.FIELD_CONTENT_ID, /*Id.escapeUid(*/uid.getUidValue()/*)*/);
}
}
/**
* Generate the fully qualified id from unqualified object {@link org.identityconnectors.framework.common.objects.Uid}
* <p/>
* The result id will be system/{@code [endSystemName]}/{@code [objectType]}/{@code [escapedObjectId]}
*
* @param uid original un escaped unique identifier of the object
* @return
*/
public URI resolveQualifiedId(Uid uid) {
if (null != uid) {
try {
return systemObjectSetId.resolveLocalId(uid.getUidValue()).getQualifiedId();
} catch (ResourceException e) {
// Should never happen in a copy constructor.
throw new UndeclaredThrowableException(e);
}
} else {
return systemObjectSetId.getQualifiedId();
}
}
/*
public ResultsHandler getResultsHandler() {
resultList.clear();
return new ConnectorObjectResultsHandler();
}
public List<Map<String, Object>> getQueryResult() {
return resultList;
}
*/
// private class ConnectorObjectResultsHandler implements ResultsHandler {
/**
* Call-back method to do whatever it is the caller wants to do with
* each {@link org.identityconnectors.framework.common.objects.ConnectorObject} that is returned in the result of
* {@link org.identityconnectors.framework.api.operations.SearchApiOp}.
*
* @param obj each object return from the search.
* @return true if we should keep processing else false to cancel.
* @throws RuntimeException the implementor should throw a {@link RuntimeException}
* that wraps any native exception (or that describes any other problem
* during execution) that is serious enough to stop the iteration.
*/
/*
public boolean handle(ConnectorObject obj) {
try {
return resultList.add(objectClassInfoHelper.build(obj, cryptoService).asMap());
} catch (IOException e) {
throw new IllegalArgumentException(e);
} catch (JsonCryptoException e) {
//TODO: This is a configuaration exception. Improve it later.
throw new IllegalArgumentException(e);
}
}
}
*/
/*
private Operator createOperator(Map<String, Object> node, final Map<String, Object> params) throws Exception {
String nodeName = getKey(node);
if (isBooleanOperator(nodeName)) {
BooleanOperator booleanOperator = OperatorFactory.createBooleanOperator(nodeName);
List<Object> parts = (List<Object>) node.get(nodeName);
if (parts.size() < 2) {
throw new IllegalArgumentException("To few elements in the 'BooleanOperator'-object (" + parts.size() + "). Must be 2 or more");
}
for (Object part : parts) {
Operator op = createOperator((Map<String, Object>) part, params);
booleanOperator.addOperator(op);
}
return booleanOperator;
} else {
return createFunctionalOperator(node, params);
}
}
private Operator createFunctionalOperator(Map<String, Object> node, final Map<String, Object> params) throws Exception {
String operatorName = getKey(node);
Map<String, Object> nodeValueMap = (Map<String, Object>) node.get(operatorName);
String field = (String) nodeValueMap.get("field");
List<String> values = (List<String>) nodeValueMap.get("values");
if (values == null) {
List<String> providedValues = (List<String>) params.get(field);
if (providedValues == null) {
throw new IllegalArgumentException("No predefined or provided values for property: " + field);
}
values = (List<String>) params.get(field);
}
return OperatorFactory.createFunctionalOperator(operatorName, objectClassInfoHelper.build(field, values, cryptoService));
}
private boolean isBooleanOperator(String key) {
return key.equals(OPERATOR_AND)
|| key.equals(OPERATOR_OR)
|| key.equals(OPERATOR_NOR)
|| key.equals(OPERATOR_NAND);
}
private String getKey(Map<String, Object> node) {
return node.keySet().isEmpty() ? null : node.keySet().iterator().next();
}
*/
}