/*
* ====================
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright 2008-2009 Sun Microsystems, Inc. All rights reserved.
*
* The contents of this file are subject to the terms of the Common Development
* and Distribution License("CDDL") (the "License"). You may not use this file
* except in compliance with the License.
*
* You can obtain a copy of the License at
* http://opensource.org/licenses/cddl1.php
* See the License for the specific language governing permissions and limitations
* under the License.
*
* When distributing the Covered Code, include this CDDL Header Notice in each file
* and include the License file at http://opensource.org/licenses/cddl1.php.
* If applicable, add the following below this CDDL Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
* ====================
*/
package org.identityconnectors.spml;
import java.text.MessageFormat;
import java.util.HashMap;
import java.util.Map;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.common.script.ScriptExecutor;
import org.identityconnectors.common.script.ScriptExecutorFactory;
import org.identityconnectors.framework.common.exceptions.ConnectorException;
import org.openspml.v2.client.Spml2Client;
import org.openspml.v2.msg.spml.ErrorCode;
import org.openspml.v2.msg.spml.ExecutionMode;
import org.openspml.v2.msg.spml.LookupRequest;
import org.openspml.v2.msg.spml.LookupResponse;
import org.openspml.v2.msg.spml.PSOIdentifier;
import org.openspml.v2.msg.spml.Request;
import org.openspml.v2.msg.spml.Response;
import org.openspml.v2.msg.spml.ReturnData;
import org.openspml.v2.msg.spml.StatusCode;
import org.openspml.v2.util.Spml2Exception;
import org.openspml.v2.util.Spml2ExceptionWithResponse;
/**
* A Connection to a SPML 2.0 Server.
*/
public class SpmlConnection {
private ScriptExecutorFactory scriptExecutorFactory;
private static final Log LOG = Log.getLog(SpmlConnection.class);
private Spml2Client client;
private SpmlConfiguration configuration;
private Map<Object, Object> memory;
private ScriptExecutor preSendExecutor;
private ScriptExecutor postReceiveExecutor;
/**
* This method is used to create a new connection for the pool.
* <p>
* Once the connection has been made, the PostConnectScript, if specified,
* is run. The following variables are made available to the
* PostConnectScript:
* <ul>
* <li>connection -- the Connection just made</li>
* <li>username -- the username specified in the Configuration</li>
* <li>password -- the password specified in the Configuration</li>
* <li>memory -- a Map<String, Object> persisted between script invocations,
* which can be used as a store</li>
* </ul>
*
* @param client
* -- The SPML2CLient used for the Connection
* @param config
* -- the SPMLConfiguration containing the connection parameters
*/
public SpmlConnection(Spml2Client client, SpmlConfiguration config) {
this.client = client;
configuration = config;
scriptExecutorFactory = ScriptExecutorFactory.newInstance(config.getScriptingLanguage());
String preCommand = configuration.getPreSendCommand();
String postCommand = configuration.getPostReceiveCommand();
try {
if (preCommand != null && preCommand.length() > 0) {
preSendExecutor =
scriptExecutorFactory.newScriptExecutor(getClass().getClassLoader(),
preCommand, true);
}
} catch (Exception e) {
throw new ConnectorException(configuration
.getMessage(SpmlMessages.PRESEND_SCRIPT_ERROR), e);
}
try {
if (postCommand != null && postCommand.length() > 0) {
postReceiveExecutor =
scriptExecutorFactory.newScriptExecutor(getClass().getClassLoader(),
postCommand, true);
}
} catch (Exception e) {
throw new ConnectorException(configuration
.getMessage(SpmlMessages.POSTRECEIVE_SCRIPT_ERROR), e);
}
memory = new HashMap<Object, Object>();
String postConnectCommand = configuration.getPostConnectCommand();
try {
if (postConnectCommand != null && postConnectCommand.length() > 0) {
ScriptExecutor executor =
scriptExecutorFactory.newScriptExecutor(getClass().getClassLoader(),
postConnectCommand, true);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("connection", this);
map.put("username", configuration.getUserName());
map.put("password", configuration.getPassword());
map.put("memory", getMemory());
executor.execute(map);
}
} catch (Exception e) {
LOG.error(e, "error in SpmlConnection constructor");
throw new ConnectorException(configuration
.getMessage(SpmlMessages.POSTCONNECT_SCRIPT_ERROR), e);
}
LOG.info("created SpmlConnection");
}
protected Map<Object, Object> getMemory() {
return memory;
}
private String toString(Request request) {
return MessageFormat.format("Request Type=''{0}'',ID=''{1}'',Mode=''{2}''", request
.getElementName(), request.getRequestID(), request.getExecutionMode());
}
/**
* Send a Request to the SPML server.
* <p>
* Before the Request is sent, the PreSendScript, if specified, is run. The
* following variables are made available to the PreSendScript:
* <ul>
* <li>request -- the SPML2 Request about to be sent</li>
* <li>memory -- a Map<String, Object> persisted between script invocations,
* which can be used as a store</li>
* </ul>
* <p>
* After the Response is received, the PostReceiveScript, if specified, is
* run. The following variables are made available to the PostReceiveScript:
* <ul>
* <li>response -- the SPML2 Response just received</li>
* <li>memory -- a Map<String, Object> persisted between script invocations,
* which can be used as a store</li>
* </ul>
*
* @param req
* -- the SPML2 Request object
* @return an SPML2 Response
* @throws Spml2ExceptionWithResponse
* @throws Spml2Exception
*/
public Response send(Request req) throws Spml2ExceptionWithResponse, Spml2Exception {
LOG.info("send(''{0}'')", toString(req));
try {
if (preSendExecutor != null) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("request", req);
map.put("memory", memory);
preSendExecutor.execute(map);
}
} catch (Exception e) {
LOG.error(e, "error in send");
throw new ConnectorException(configuration
.getMessage(SpmlMessages.PRESEND_SCRIPT_ERROR), e);
}
Response response = client.send(req);
try {
if (postReceiveExecutor != null) {
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("response", response);
map.put("memory", memory);
postReceiveExecutor.execute(map);
}
} catch (Exception e) {
LOG.error(e, "error in receive");
throw new ConnectorException(configuration
.getMessage(SpmlMessages.POSTRECEIVE_SCRIPT_ERROR), e);
}
return response;
}
/**
* Disposes of a Connection.
* <p>
* Before the Connection is disposed, the PreDisconnectScript, if specified,
* is run. The following variables are made available to the
* PreDisconnectScript:
* <ul>
* <li>connection -- the Connection about to be disposed</li>
* <li>username -- the username specified in the Configuration</li>
* <li>password -- the password specified in the Configuration</li>
* <li>memory -- a Map<String, Object> persisted between script invocations,
* which can be used as a store</li>
* </ul>
* See {@link org.identityconnectors.framework.spi.Connector#dispose()}
*/
public void dispose() {
String preCommand = configuration.getPreDisconnectCommand();
if (preCommand != null && preCommand.length() > 0) {
ScriptExecutor executor =
scriptExecutorFactory.newScriptExecutor(getClass().getClassLoader(),
preCommand, true);
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("connection", this);
map.put("username", configuration.getUserName());
map.put("password", configuration.getPassword());
map.put("memory", memory);
try {
executor.execute(map);
} catch (Exception e) {
throw new ConnectorException(configuration
.getMessage(SpmlMessages.PREDISCONNECT_SCRIPT_ERROR), e);
}
}
}
/**
*
* See {@link org.identityconnectors.framework.spi.operations.TestOp#test()}
* .
*/
public void test() {
try {
if (configuration.getTargetNames() == null
|| configuration.getTargetNames().length == 0) {
throw new ConnectorException(configuration
.getMessage(SpmlMessages.MAPPING_REQUIRED));
}
get("random name", configuration.getTargetNames()[0]);
} catch (Exception e) {
throw ConnectorException.wrap(e);
}
}
private void get(String uid, String targetId) {
try {
LookupRequest request = new LookupRequest();
PSOIdentifier psoId = new PSOIdentifier();
psoId.setTargetID(targetId);
psoId.setID(uid);
LOG.info("get(''{0}'')", uid);
request.setPsoID(psoId);
request.setRequestID(uid);
request.setReturnData(ReturnData.EVERYTHING);
request.setExecutionMode(ExecutionMode.SYNCHRONOUS);
LookupResponse response = (LookupResponse) send(request);
if (!response.getStatus().equals(StatusCode.SUCCESS)
&& response.getError() != ErrorCode.NO_SUCH_IDENTIFIER) {
throw new ConnectorException(asString(response.getErrorMessages()));
}
} catch (Spml2ExceptionWithResponse e) {
LOG.error(e, "get failed:''{0}''", e.getResponse().getError());
if (e.getResponse().getError() != ErrorCode.NO_SUCH_IDENTIFIER) {
throw new ConnectorException(asString(e.getResponse().getErrorMessages()));
}
} catch (Exception e) {
LOG.error(e, "get failed");
throw ConnectorException.wrap(e);
}
}
protected String asString(String[] strings) {
if (strings.length == 0) {
return "";
}
StringBuilder buffer = new StringBuilder();
for (String string : strings) {
buffer.append("\n" + string);
}
return buffer.toString().substring(1);
}
}