• Views
  • Iteration Report
  • My Iteration Report
  •  
OMERO.server
  • Login
  • Help/Guide
  • About Trac
  • Preferences
  • Wiki
  • Timeline
  • Roadmap
  • Browse Source
  • View Tickets
  • Search

Context Navigation

  • Last Change
  • Annotate
  • Revision Log

root/trunk/components/common/src/ome/system/OmeroContext.java

Revision 2996, 14.2 kB (checked in by jmoore, 3 months ago)

ticket:1114 - Fix for timeToLive leaks in SessionCache

  • New strategy for OmeroContext.publishEvent() (r2605, r2654)
  • Added "updateInterval" to SessionCache
  • Removed "needsUpdate" from SessionCache
  • Refactoring MockFixture & test.xml for a complicated blitz test
  • Property svn:keywords set to
    Date
    Revision
    Id
    URL
Line 
1/*
2 *   $Id$
3 *
4 *   Copyright 2006 University of Dundee. All rights reserved.
5 *   Use is subject to license terms supplied in LICENSE.txt
6 */
7
8package ome.system;
9
10// Java imports
11import java.util.ArrayList;
12import java.util.LinkedList;
13import java.util.List;
14import java.util.Properties;
15
16import ome.api.ServiceInterface;
17import ome.conditions.ApiUsageException;
18import ome.util.messages.InternalMessage;
19import ome.util.messages.MessageException;
20
21import org.springframework.beans.BeansException;
22import org.springframework.beans.factory.BeanFactory;
23import org.springframework.beans.factory.config.BeanDefinition;
24import org.springframework.beans.factory.config.ConstructorArgumentValues;
25import org.springframework.beans.factory.config.TypedStringValue;
26import org.springframework.beans.factory.config.ConstructorArgumentValues.ValueHolder;
27import org.springframework.beans.factory.support.RootBeanDefinition;
28import org.springframework.context.ApplicationContext;
29import org.springframework.context.ApplicationEvent;
30import org.springframework.context.ConfigurableApplicationContext;
31import org.springframework.context.access.ContextSingletonBeanFactoryLocator;
32import org.springframework.context.event.ApplicationEventMulticaster;
33import org.springframework.context.support.ClassPathXmlApplicationContext;
34import org.springframework.context.support.StaticApplicationContext;
35
36/**
37 * Provides static access for the creation of singleton and non-singleton
38 * application contexts. Also provides context names as constant fields which
39 * can be used for the lookup of particular contexts, through either
40 * {@link #getInstance(String)} or
41 * {@link ome.system.ServiceFactory#ServiceFactory(String)}.
42 *
43 * By passing a {@link java.util.Properties} instance into the
44 * {@link #getClientContext(Properties)} method, a non-static version is
45 * created. Currently this is only supported for the client context.
46 *
47 * @author <br>
48 *         Josh Moore &nbsp;&nbsp;&nbsp;&nbsp; <a
49 *         href="mailto:josh.moore@gmx.de"> josh.moore@gmx.de</a>
50 * @since OME3.0
51 */
52public class OmeroContext extends ClassPathXmlApplicationContext {
53    /**
54     * identifier for an OmeroContext configured in
55     * classpath*:beanRefContext.xml for use by remote (via JNDI/RMI) clients.
56     */
57    public final static String CLIENT_CONTEXT = "ome.client";
58
59    /**
60     * identifier for an OmeroContext configured in
61     * classpath*:beanRefContext.xml for use by server-side processes. All
62     * objects obtained from the context are in a state for immediate use.
63     */
64    public final static String MANAGED_CONTEXT = "ome.server";
65
66    private static OmeroContext _client;
67
68    private static OmeroContext _managed;;
69
70    /**
71     * Multicaster used by this instance. Unlike other Spring application
72     * contexts, this context assumes that a "global multicaster" is configured
73     * and so does not pass messages to the parent context, but assumes that
74     * the multicaster will do this. In order to implement this logic, it is
75     * necessary to lookup the entity by name, since all getters and fields
76     * are private in the superclasses.
77     */
78    private ApplicationEventMulticaster multicaster;
79   
80    // ~ Constructors
81    // =========================================================================
82
83    public OmeroContext(String configLocation) throws BeansException {
84        super(configLocation);
85    }
86
87    public OmeroContext(String[] configLocations) throws BeansException {
88        super(configLocations);
89    }
90
91    public OmeroContext(String[] configLocations, boolean refresh)
92            throws BeansException {
93        super(configLocations, refresh);
94    }
95
96    public OmeroContext(String[] configLocations, ApplicationContext parent)
97            throws BeansException {
98        super(configLocations, parent);
99    }
100
101    public OmeroContext(String[] configLocations, boolean refresh,
102            ApplicationContext parent) throws BeansException {
103        super(configLocations, refresh, parent);
104    }
105
106    // ~ Creation
107    // =========================================================================
108
109    private final static Object mutex = new Object();
110
111    /**
112     * create (if necessary) and return the single default client OmeroContext.
113     * Any two calls to this method will return the same (==) context instance.
114     *
115     * @see #CLIENT_CONTEXT
116     */
117    public static OmeroContext getClientContext() {
118        synchronized (mutex) {
119            if (_client == null) {
120                _client = getInstance(CLIENT_CONTEXT);
121            }
122
123            return _client;
124        }
125    }
126
127    /**
128     * initialize a new client OmeroContext (named {@link #CLIENT_CONTEXT}),
129     * using the {@link #getContext(Properties, String)} method.
130     *
131     * @see #getContext(Properties, String)
132     * @see #CLIENT_CONTEXT
133     * @see ServiceFactory#ServiceFactory(Login)
134     * @see ServiceFactory#ServiceFactory(Server)
135     * @see ServiceFactory#ServiceFactory(Properties)
136     */
137    public static OmeroContext getClientContext(Properties props) {
138        return getContext(props, CLIENT_CONTEXT);
139    }
140
141    /**
142     * initialize a new client OmeroContext using the {@link Properties}
143     * provided as values for property (e.g. ${name}) replacement in Spring. Two
144     * calls to this method with the same argument will return different ( =! )
145     * contexts.
146     *
147     * @param props
148     *            Non-null properties for replacement.
149     * @param context
150     *            Non-null name of context to find in beanRefContext.xml
151     *
152     * @see ServiceFactory#ServiceFactory(Login)
153     * @see ServiceFactory#ServiceFactory(Server)
154     * @see ServiceFactory#ServiceFactory(Properties)
155     */
156    public static OmeroContext getContext(Properties props, String context) {
157        if (props == null || context == null) {
158            throw new ApiUsageException("Arguments may not be null.");
159        }
160
161        Properties copy = new Properties(props);
162        ConstructorArgumentValues ctorArg = new ConstructorArgumentValues();
163        ctorArg.addGenericArgumentValue(copy);
164        BeanDefinition definition = new RootBeanDefinition(Properties.class,
165                ctorArg, null);
166        StaticApplicationContext staticContext = new StaticApplicationContext();
167        staticContext.registerBeanDefinition("properties", definition);
168        staticContext.refresh();
169
170        OmeroContext ctx = new Locator().lookup(context, staticContext);
171        return ctx;
172    }
173
174    /**
175     * create (if necessary) and return the single default managed OmeroContext.
176     * Any two calls to this method will return the same (==) context instance.
177     * Managed means that the services are fully wrapped by interceptors, and
178     * are essentially the services made available remotely.
179     *
180     * @see #INTERNAL_CONTEXT
181     */
182    public static OmeroContext getManagedServerContext() {
183        synchronized (mutex) {
184            if (_managed == null) {
185                _managed = getInstance(MANAGED_CONTEXT);
186            }
187
188            return _managed;
189        }
190
191    }
192
193    /**
194     * create (if necessary) and return the single default OmeroContext named by
195     * the beanFactoryName parameter. Any two calls to this method with the same
196     * parameter will return the same (==) context instance.
197     *
198     * @see #getClientContext()
199     * @see #getInternalServerContext()
200     * @see #getManagedServerContext()
201     */
202    public static OmeroContext getInstance(String beanFactoryName) {
203        OmeroContext ctx = (OmeroContext) ContextSingletonBeanFactoryLocator
204                .getInstance().useBeanFactory(beanFactoryName).getFactory();
205        try {
206            ctx.getBeanFactory();
207        } catch (IllegalStateException ise) {
208            // Here we catch IllegalStateException because it implies that
209            // the bean factory isn't created yet. However, if that goes
210            // wrong, we need to rollback.
211            try {
212                ctx.refresh();
213            } catch (RuntimeException re) {
214                if (ctx != null) {
215                    try {
216                        ctx.close();
217                    } catch (Exception e) {
218                        // OK ignoring to rethrow the original exception
219                    }
220                }
221                throw re;
222            }
223        }
224        return ctx;
225    }
226
227    // ~ Utilities
228    // =========================================================================
229
230    /**
231     * Uses the methods of this context's {@link BeanFactory} to autowire any
232     * Object based on the given beanName.
233     *
234     * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#applyBeanPropertyValues(java.lang.Object,
235     *      java.lang.String)
236     */
237    public void applyBeanPropertyValues(Object target, String beanName) {
238        this.getAutowireCapableBeanFactory().applyBeanPropertyValues(target,
239                beanName);
240    }
241
242    /**
243     * Uses the methods of this context's {@link BeanFactory} to autowire any
244     * Object based on the service class. This is used by
245     * {@link SelfConfigurableService} instances to acquire dependencies.
246     *
247     * @see SelfConfigurableService
248     * @see org.springframework.beans.factory.config.AutowireCapableBeanFactory#applyBeanPropertyValues(java.lang.Object,
249     *      java.lang.String)
250     */
251    public void applyBeanPropertyValues(Object target,
252            Class<? extends ServiceInterface> beanInterface) {
253        // TODO: it would be better to have this as <? extends
254        // SelfConfigurableService>
255        // but there are issues because of the ApplicationContextAware. Perhaps
256        // we can combine them later.
257        applyBeanPropertyValues(target, "internal-" + beanInterface.getName());
258    }
259
260    /**
261     * refreshes all the nested OmeroContexts within this instance. This is
262     * useful when using a static context, and {@link Properties} which were
263     * pulled from {@link System#getProperties()} have been changed.
264     *
265     * If this is a server-side instance ({@link OmeroContext#MANAGED_CONTEXT}
266     * or {@link OmeroContext#INTERNAL_CONTEXT}), this may take a significant
267     * amount of time.
268     *
269     * @see org.springframework.context.ConfigurableApplicationContext#refresh()
270     */
271    public void refreshAll() {
272        ApplicationContext ac = this;
273        List<ConfigurableApplicationContext> list = new LinkedList<ConfigurableApplicationContext>();
274        while (ac instanceof ConfigurableApplicationContext) {
275            list.add((ConfigurableApplicationContext) ac);
276            ac = ac.getParent();
277        }
278
279        for (int i = list.size() - 1; i >= 0; i--) {
280            list.get(i).refresh();
281        }
282
283    }
284
285    /**
286     * closes all the nested OmeroContexts within this instance.
287     *
288     * If this is a server-side instance ({@link OmeroContext#MANAGED_CONTEXT}
289     * or {@link OmeroContext#INTERNAL_CONTEXT}), this may take a significant
290     * amount of time.
291     *
292     * @see org.springframework.context.ConfigurableApplicationContext#close()
293     */
294    public void closeAll() {
295        ApplicationContext ac = this;
296        List<ConfigurableApplicationContext> list = new LinkedList<ConfigurableApplicationContext>();
297        while (ac instanceof ConfigurableApplicationContext) {
298            list.add((ConfigurableApplicationContext) ac);
299            ac = ac.getParent();
300        }
301
302        for (int i = list.size() - 1; i >= 0; i--) {
303            list.get(i).close();
304        }
305
306    }
307
308    public String getProperty(String propertyName) {
309        PreferenceContext pc = (PreferenceContext) getBean("preferenceContext");
310        return pc.getProperty(propertyName);
311    }
312
313    @Override
314    public void publishEvent(ApplicationEvent event) {
315        multicaster.multicastEvent(event);
316    }
317   
318    /**
319     * Convenience method around
320     * {@link #publishEvent(org.springframework.context.ApplicationEvent)} which
321     * catches all {@link MessageException} and unwraps the contained
322     * {@link Throwable} instance and rethrows.
323     *
324     * @param msg
325     * @throws Throwable
326     */
327    public void publishMessage(InternalMessage msg) throws Throwable {
328        try {
329            publishEvent(msg);
330        } catch (MessageException me) {
331            throw me.getException();
332        }
333    }
334   
335    @Override
336    protected void onRefresh() throws BeansException {
337        super.onRefresh();
338        multicaster = (ApplicationEventMulticaster) getBean("applicationEventMulticaster");
339    }
340
341    // ~ Non-singleton locator
342    // =========================================================================
343
344    /**
345     * provides access to the protected methods of
346     * {@link org.springframework.context.access.ContextSingletonBeanFactoryLocator}
347     * which cannot be used externally.
348     */
349    protected static class Locator extends ContextSingletonBeanFactoryLocator {
350        // copied from ContextSingletonBeanFactoryLocator
351        private static final String BEANS_REFS_XML_NAME = "classpath*:beanRefContext.xml";
352
353        public Locator() {
354            super(null);
355        }
356
357        /**
358         * uses
359         * {@link ContextSingletonBeanFactoryLocator#createDefinition(java.lang.String, java.lang.String)}
360         * and
361         * {@link ContextSingletonBeanFactoryLocator#initializeDefinition(org.springframework.beans.factory.BeanFactory)}
362         * to create a new context from a given definition.
363         */
364        public OmeroContext lookup(String selector, ApplicationContext parent) {
365            ConfigurableApplicationContext beanRefContext = (ConfigurableApplicationContext) createDefinition(
366                    BEANS_REFS_XML_NAME, "manual");
367            initializeDefinition(beanRefContext);
368
369            BeanDefinition definition = beanRefContext.getBeanFactory()
370                    .getBeanDefinition(selector);
371            ValueHolder holder = definition.getConstructorArgumentValues()
372                    .getGenericArgumentValue(List.class);
373            List<TypedStringValue> files = (List<TypedStringValue>) holder
374                    .getValue();
375            List<String> fileStrings = new ArrayList<String>(files.size());
376            for (TypedStringValue tsv : files) {
377                fileStrings.add(tsv.getValue());
378            }
379
380            OmeroContext c = new OmeroContext(fileStrings
381                    .toArray(new String[0]), true, parent);
382
383            return c;
384        }
385
386    }
387
388}
Note: See TracBrowser for help on using the browser.

Download in other formats:

  • Plain Text
  • Original Format

Trac Powered

Powered by Trac 0.11
By Edgewall Software.

Visit the Trac open source project at
http://trac.edgewall.org/