package org.infinispan.jcache.remote; import static org.jboss.as.controller.client.helpers.ClientConstants.ADD; import static org.jboss.as.controller.client.helpers.ClientConstants.COMPOSITE; import static org.jboss.as.controller.client.helpers.ClientConstants.NAME; import static org.jboss.as.controller.client.helpers.ClientConstants.OP; import static org.jboss.as.controller.client.helpers.ClientConstants.OP_ADDR; import static org.jboss.as.controller.client.helpers.ClientConstants.OUTCOME; import static org.jboss.as.controller.client.helpers.ClientConstants.READ_ATTRIBUTE_OPERATION; import static org.jboss.as.controller.client.helpers.ClientConstants.REMOVE_OPERATION; import static org.jboss.as.controller.client.helpers.ClientConstants.RESULT; import static org.jboss.as.controller.client.helpers.ClientConstants.STEPS; import static org.jboss.as.controller.client.helpers.ClientConstants.SUBSYSTEM; import static org.jboss.as.controller.client.helpers.ClientConstants.SUCCESS; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.Properties; import java.util.concurrent.atomic.AtomicBoolean; import org.infinispan.client.hotrod.RemoteCacheContainer; import org.infinispan.commons.logging.LogFactory; import org.infinispan.commons.util.TypedProperties; import org.infinispan.jcache.remote.logging.Log; import org.jboss.as.controller.PathAddress; import org.jboss.as.controller.client.ModelControllerClient; import org.jboss.dmr.ModelNode; interface RemoteCacheAccess { void addCacheIfAbsent(final String cacheName); void removeCache(final String cacheName); String MANAGED_ACCESS = "infinispan.jcache.remote.managed_access"; static RemoteCacheAccess createCacheAccess(RemoteCacheContainer rm, Properties p) { TypedProperties tp = new TypedProperties(p); boolean managedAccess = tp.getBooleanProperty(MANAGED_ACCESS, true); return managedAccess ? new ManagedAccess(rm.getConfiguration().servers().get(0).host(), 9990) : new UnmanagedAccess(rm); } final class ManagedAccess implements RemoteCacheAccess { private static final Log log = LogFactory.getLog(ManagedAccess.class, Log.class); private static final String INFINISPAN_SUBSYSTEM_NAME = "datagrid-infinispan"; private static final String INFINISPAN_ENDPOINT_SUBSYSTEM_NAME = "datagrid-infinispan-endpoint"; private final String host; private final int port; ManagedAccess(String host, int port) { this.host = host; this.port = port; } private void checkExistence(final String cacheType, final String cacheName, final AtomicBoolean result) throws ManagementClientException { if (!result.get()) { withManagementClient(host, port, new ManagementRunnable() { @Override public void run(ModelControllerClient client) throws Exception { PathAddress pathAddress = PathAddress.pathAddress(SUBSYSTEM, INFINISPAN_SUBSYSTEM_NAME) .append("cache-container", getHotRodCacheContainer(client)) .append(cacheType, cacheName); ModelNode op = new ModelNode(); op.get(OP).set(READ_ATTRIBUTE_OPERATION); op.get(OP_ADDR).set(pathAddress.toModelNode()); op.get(NAME).set("configuration"); ModelNode resp = client.execute(op); if (SUCCESS.equals(resp.get(OUTCOME).asString())) { result.set(true); } } }); } } private boolean containsCache(final String cacheName) throws NotAvailableException, ManagementClientException { checkServerManagementAvailable(); final AtomicBoolean result = new AtomicBoolean(false); checkExistence("local-cache", cacheName, result); checkExistence("distributed-cache", cacheName, result); checkExistence("replicated-cache", cacheName, result); checkExistence("invalidation-cache", cacheName, result); return result.get(); } private void addCache(final String cacheName) throws NotAvailableException, ManagementClientException { checkServerManagementAvailable(); withManagementClient(host, port, new ManagementRunnable() { @Override public void run(ModelControllerClient client) throws Exception { final ModelNode composite = new ModelNode(); composite.get(OP).set(COMPOSITE); composite.get(OP_ADDR).setEmptyList(); final ModelNode steps = composite.get(STEPS); final ModelNode configAddOp = steps.add(); configAddOp.get(OP).set(ADD); String cacheContainer = getHotRodCacheContainer(client); configAddOp.get(OP_ADDR).set(PathAddress.pathAddress(SUBSYSTEM, INFINISPAN_SUBSYSTEM_NAME) .append("cache-container", cacheContainer) .append("configurations", "CONFIGURATIONS") .append("local-cache-configuration", cacheName).toModelNode()); configAddOp.get("template").set(false); final ModelNode cacheAddOp = steps.add(); cacheAddOp.get(OP).set(ADD); cacheAddOp.get(OP_ADDR).set(PathAddress.pathAddress(SUBSYSTEM, INFINISPAN_SUBSYSTEM_NAME) .append("cache-container", cacheContainer) .append("local-cache", cacheName).toModelNode()); cacheAddOp.get("configuration").set(cacheName); ModelNode resp = client.execute(composite); if (!SUCCESS.equals(resp.get(OUTCOME).asString())) { System.err.println(resp); throw new IllegalArgumentException(resp.asString()); } } }); } @Override public void addCacheIfAbsent(String cacheName) { try { if (!containsCache(cacheName)) { addCache(cacheName); } } catch (NotAvailableException ex) { //Nothing to do. } catch (ManagementClientException ex) { throw log.cacheCreationFailed(cacheName, ex); } } @Override public void removeCache(final String cacheName) { try { checkServerManagementAvailable(); withManagementClient(host, port, new ManagementRunnable() { @Override public void run(ModelControllerClient client) throws Exception { final ModelNode composite = new ModelNode(); composite.get(OP).set(COMPOSITE); composite.get(OP_ADDR).setEmptyList(); final ModelNode steps = composite.get(STEPS); final ModelNode cacheRemoveOp = steps.add(); cacheRemoveOp.get(OP).set(REMOVE_OPERATION); String cacheContainer = getHotRodCacheContainer(client); cacheRemoveOp.get(OP_ADDR).set(PathAddress.pathAddress(SUBSYSTEM, INFINISPAN_SUBSYSTEM_NAME) .append("cache-container", cacheContainer) .append("local-cache", cacheName).toModelNode()); final ModelNode configRemoveOp = steps.add(); configRemoveOp.get(OP).set(REMOVE_OPERATION); configRemoveOp.get(OP_ADDR).set(PathAddress.pathAddress(SUBSYSTEM, INFINISPAN_SUBSYSTEM_NAME) .append("cache-container", cacheContainer) .append("configurations", "CONFIGURATIONS") .append("local-cache-configuration", cacheName).toModelNode()); ModelNode resp = client.execute(composite); if (!SUCCESS.equals(resp.get(OUTCOME).asString())) { //TODO: don't ignore failures other than "resource doens't exist" System.err.println(resp); } } }); } catch (NotAvailableException ex) { // Nothing to do. } catch (ManagementClientException ex) { throw log.serverManagementOperationFailed(ex); } } private String getHotRodCacheContainer(ModelControllerClient client) throws IOException { PathAddress pathAddress = PathAddress.pathAddress(SUBSYSTEM, INFINISPAN_ENDPOINT_SUBSYSTEM_NAME) .append("hotrod-connector", "hotrod-connector"); ModelNode op = new ModelNode(); op.get(OP).set(READ_ATTRIBUTE_OPERATION); op.get(OP_ADDR).set(pathAddress.toModelNode()); op.get("name").set("cache-container"); ModelNode resp = client.execute(op); if (!SUCCESS.equals(resp.get(OUTCOME).asString())) { throw new IllegalArgumentException(resp.asString()); } return resp.get(RESULT).asString(); } private static void withManagementClient(String host, int port, ManagementRunnable runnable) throws ManagementClientException { InetAddress addr; try { addr = InetAddress.getByName(host); } catch (UnknownHostException ex) { throw new ManagementClientException(String.format("Failed to resolve host '%s'.", host), ex); } ModelControllerClient client = ModelControllerClient.Factory.create("http-remoting", addr, port); try { runnable.run(client); } catch (Exception ex) { throw new ManagementClientException("", ex); } finally { try { client.close(); } catch (IOException e) { // Ignore } } } /** * wildfly-controller is an optional dependency * * @throws NotAvailableException */ private static void checkServerManagementAvailable() throws NotAvailableException { try { boolean skipServerMgmtLookup = Boolean.parseBoolean(System.getProperty("infinispan.jcache.mgmt.lookup.skip", "false")); if (skipServerMgmtLookup) { throw new NotAvailableException(); } Class.forName("org.jboss.as.controller.client.ModelControllerClient"); } catch (ClassNotFoundException e) { throw new NotAvailableException(); } } private interface ManagementRunnable { void run(ModelControllerClient client) throws Exception; } public static class NotAvailableException extends Exception { private static final long serialVersionUID = 2036495722939416728L; public NotAvailableException() { } public NotAvailableException(String message, Throwable cause) { super(message, cause); } } public static class ManagementClientException extends Exception { private static final long serialVersionUID = -5857650491476258495L; public ManagementClientException() { } public ManagementClientException(String message, Throwable cause) { super(message, cause); } } } final class UnmanagedAccess implements RemoteCacheAccess { static final Log log = LogFactory.getLog(UnmanagedAccess.class, Log.class); private final RemoteCacheContainer rm; UnmanagedAccess(RemoteCacheContainer rm) { this.rm = rm; } @Override public void addCacheIfAbsent(String cacheName) { if (rm.getCache(cacheName) != null) throw log.cacheNamePredefined(cacheName); throw log.createCacheNotAllowedWithoutManagement(); } @Override public void removeCache(String cacheName) { throw log.removeCacheNotAllowedWithoutManagement(); } } }