/* * Copyright 2008 the original author or authors. * * Licensed 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 org.rioproject.impl.opstring; import net.jini.admin.Administrable; import net.jini.config.ConfigurationException; import net.jini.core.discovery.LookupLocator; import net.jini.core.lookup.ServiceItem; import net.jini.core.lookup.ServiceTemplate; import net.jini.discovery.DiscoveryManagement; import net.jini.lookup.LookupCache; import net.jini.lookup.ServiceDiscoveryEvent; import org.rioproject.deploy.DeployAdmin; import org.rioproject.deploy.ProvisionManager; import org.rioproject.impl.client.DiscoveryManagementPool; import org.rioproject.impl.client.LookupCachePool; import org.rioproject.impl.client.ServiceDiscoveryAdapter; import org.rioproject.opstring.OperationalStringManager; import org.rioproject.impl.util.ThrowableUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.rmi.RemoteException; import java.util.ArrayList; import java.util.List; /** * A generated proxy to assist with the management of {@link org.rioproject.opstring.OperationalStringManager} instances. * * @author Dennis Reedy */ public class OpStringManagerProxy { private static DiscoveryManagement discoMgmt; /** * Create a dynamic proxy for OperationalStringManager * management. Invoking this method relies on this utility having it's * DiscoveryManagement property set. * * @param name The name of the OperationalString. This must not be null. * @param manager The primary (managing) OperationalStringManager * * @return A generated proxy * * @throws ConfigurationException If the LookupCachePool cannot be accessed * or created * @throws IOException If DiscoveryManagement has problems */ public static OperationalStringManager getProxy(String name, OperationalStringManager manager) throws ConfigurationException, IOException { if(discoMgmt==null) { throw new IllegalStateException("DiscoveryManagement has not been set into proxy"); } return (OperationalStringManager) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{OpStringManager.class}, new OpStringManagerDispatcher(name, manager, discoMgmt)); } /** * Create a dynamic proxy for OperationalStringManager management * * @param name The name of the OperationalString. This must not be null. * @param manager The primary (managing) OperationalStringManager * @param dMgr DiscoveryManagement instance to use. This must not be null. * * @return A generated proxy * * @throws ConfigurationException If the LookupCachePool cannot be accessed * or created * @throws IOException If DiscoveryManagement has problems */ public static OperationalStringManager getProxy(String name, OperationalStringManager manager, DiscoveryManagement dMgr) throws ConfigurationException, IOException { assert name!=null; assert dMgr!=null; if(discoMgmt==null) discoMgmt = dMgr; return (OperationalStringManager) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class[]{OpStringManager.class}, new OpStringManagerDispatcher(name, manager, dMgr)); } /** * A CGLIB dispatcher for managing the invocation of methods to the * primary {@link OperationalStringManager} instance. */ public static class OpStringManagerDispatcher extends ServiceDiscoveryAdapter implements InvocationHandler { String name; OperationalStringManager manager; DiscoveryManagement dMgr; LookupCache lCache; boolean terminated = false; final List<ProvisionManager> monitors = new ArrayList<ProvisionManager>(); final Logger logger = LoggerFactory.getLogger(OpStringManagerDispatcher.class); public OpStringManagerDispatcher(String name, OperationalStringManager manager, DiscoveryManagement dMgr) throws ConfigurationException, IOException { this.name = name; this.manager = manager; this.dMgr = dMgr; ServiceTemplate template = new ServiceTemplate(null, new Class[] {ProvisionManager.class}, null); lCache = LookupCachePool.getInstance().getLookupCache(dMgr, template); if(lCache instanceof LookupCachePool.SharedLookupCache) { LookupCachePool.SharedLookupCache sCache = (LookupCachePool.SharedLookupCache)lCache; for(ServiceItem item : sCache.lookupRemote(null, Integer.MAX_VALUE)) { synchronized(monitors) { monitors.add((ProvisionManager) item.service); } } } else { for(ServiceItem item : lCache.lookup(null, Integer.MAX_VALUE)) { synchronized(monitors) { monitors.add((ProvisionManager) item.service); } } } lCache.addListener(this); } public void serviceAdded(ServiceDiscoveryEvent event) { ServiceItem item = event.getPostEventServiceItem(); synchronized(monitors) { ProvisionManager monitor = (ProvisionManager)item.service; if(!monitors.contains(monitor)) monitors.add(monitor); } } public void serviceRemoved(ServiceDiscoveryEvent event) { ServiceItem item = event.getPreEventServiceItem(); ProvisionManager m = (ProvisionManager)item.service; synchronized(monitors) { monitors.remove(m); } lCache.discard(m); } OperationalStringManager getManager() throws Throwable { OperationalStringManager opMgr = null; ProvisionManager monitor; synchronized(monitors) { if(!monitors.isEmpty()) monitor = monitors.get(0); else { StringBuilder sb = new StringBuilder(); if(dMgr instanceof DiscoveryManagementPool.SharedDiscoveryManager) { DiscoveryManagementPool.SharedDiscoveryManager sdm = (DiscoveryManagementPool.SharedDiscoveryManager)dMgr; sb.append("Using discovery attributes: "); if(sdm.getGroups()!=null) { sb.append("groups=["); int i=0; for(String s : sdm.getGroups()) { if(i>0) sb.append(", "); sb.append(s); i++; } sb.append("]"); } if(sdm.getLocators()!=null) { sb.append(" "); sb.append("locators=["); int i=0; for(LookupLocator l : sdm.getLocators()) { if(i>0) sb.append(", "); sb.append(l.toString()); i++; } sb.append("] "); } } throw new RemoteException("No ProvisionMonitor instances available. "+sb.toString()); } } /* If we get an OperationalStringException getting the primary * manager, retry before re-throwing the exception. This is to * allow for a backup ProvisionMonitor to take over */ Throwable toThrow = null; for(int i=0; i<3; i++) { if(terminated) break; try { DeployAdmin dAdmin = (DeployAdmin)((Administrable)monitor).getAdmin(); opMgr = dAdmin.getOperationalStringManager(name); toThrow = null; break; } catch(Throwable t) { //t.printStackTrace(); toThrow = t; try { Thread.sleep(500); } catch (InterruptedException e1) { /* ignore */ } if(!ThrowableUtil.isRetryable(t)) { synchronized(monitors) { if(!monitors.isEmpty()) monitors.remove(monitor); else toThrow = t; } } } } if(toThrow!=null) throw toThrow; return opMgr; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if(terminated) { throw new IllegalStateException("The OpStringManagerDispatcher has been terminated, " + "invocations through this utility are not possible " + "in it's current state. Make sure all invoking " + "threads are terminated to resolve this issue"); } if(method.getName().equals("terminate")) { lCache.removeListener(this); monitors.clear(); terminated = true; logger.debug("Terminated OpStringManagerDispatcher"); return null; } while(!terminated) { try { if(manager.isManaging()) break; manager = getManager(); } catch (Throwable t) { if(terminated) break; if(!ThrowableUtil.isRetryable(t)) { manager = getManager(); } else { throw t; } } } if(terminated) return null; return method.invoke(manager, args); } } public static void setDiscoveryManagement(DiscoveryManagement dMgr) { discoMgmt = dMgr; } public static DiscoveryManagement getDiscoveryManagement() { return discoMgmt; } public static interface OpStringManager extends OperationalStringManager { void terminate(); } }