/*
* ====================
* 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]"
* ====================
* Portions Copyrighted 2010-2013 ForgeRock AS.
*/
package org.identityconnectors.framework.impl.api.local.operations;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.identityconnectors.common.logging.Log;
import org.identityconnectors.framework.impl.api.local.ObjectPool;
import org.identityconnectors.framework.impl.api.local.ObjectPoolEntry;
import org.identityconnectors.framework.spi.Connector;
import org.identityconnectors.framework.spi.PoolableConnector;
/**
* Proxy for APIOperationRunner that takes care of setting up underlying
* connector and creating the implementation of APIOperationRunner.
* The implementation of APIOperationRunner gets created whenever the
* actual method is invoked.
*/
public class ConnectorAPIOperationRunnerProxy implements InvocationHandler {
private static final Log LOG = Log.getLog(ConnectorAPIOperationRunnerProxy.class);
/**
* The operational context
*/
private final ConnectorOperationalContext context;
/**
* The implementation constructor. The instance is lazily created upon
* invocation
*/
private final Constructor<? extends APIOperationRunner> runnerImplConstructor;
/**
* Create an APIOperationRunnerProxy
* @param context The operational context
* @param runnerImplConstructor The implementation constructor. Implementation
* must define a two-argument constructor(OperationalContext,Connector)
*/
public ConnectorAPIOperationRunnerProxy(ConnectorOperationalContext context,
Constructor<? extends APIOperationRunner> runnerImplConstructor) {
this.context = context;
this.runnerImplConstructor = runnerImplConstructor;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
//do not proxy equals, hashCode, toString
if (method.getDeclaringClass() == Object.class) {
return method.invoke(this, args);
}
Object ret = null;
Connector connector = null;
ObjectPool<PoolableConnector> pool = context.getPool();
ObjectPoolEntry<PoolableConnector> poolEntry = null;
// get the connector class..
Class<? extends Connector> connectorClazz = context.getConnectorClass();
try {
// pooling is implemented get one..
if (pool != null) {
poolEntry = pool.borrowObject();
connector = poolEntry.getPooledObject();
}
else {
// get a new instance of the connector..
connector = connectorClazz.newInstance();
// initialize the connector..
connector.init(context.getConfiguration());
}
APIOperationRunner runner =
runnerImplConstructor.newInstance(context,connector);
ret = method.invoke(runner, args);
// call out to the operation..
} catch (InvocationTargetException e) {
Throwable root = e.getCause();
throw root;
} finally {
// make sure dispose of the connector properly
if (connector != null) {
// determine if there was a pool..
if (poolEntry != null) {
try {
//try to return it to the pool even though an
//exception may have happened that leaves it in
//a bad state. The contract of checkAlive
//is that it will tell you if the connector is
//still valid and so we leave it up to the pool
//and connector to work it out.
poolEntry.close();
} catch (Exception e) {
//don't let pool exceptions propagate or mask
//other exceptions. do log it though.
LOG.error(e, null);
}
}
//not pooled - just dispose
else {
//dispose it not supposed to throw, but just in case,
//catch the exception and log it so we know about it
//but don't let the exception prevent additional
//cleanup that needs to happen
try {
connector.dispose();
} catch (Exception e) {
//log this though
LOG.error(e, null);
}
}
}
}
return ret;
}
}