• 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/server/src/ome/services/query/Query.java

Revision 1932, 11.2 kB (checked in by Aleksandra Tarkowska, 14 months ago)

more changes for r1931

  • Property svn:keywords set to
    Date
    Revision
    Id
    URL
Line 
1/*
2 * ome.services.query.Query
3 *
4 *   Copyright 2006 University of Dundee. All rights reserved.
5 *   Use is subject to license terms supplied in LICENSE.txt
6 */
7
8/*------------------------------------------------------------------------------
9 *
10 * Written by:    Josh Moore <josh.moore@gmx.de>
11 *
12 *------------------------------------------------------------------------------
13 */
14
15package ome.services.query;
16
17// Java imports
18import java.sql.SQLException;
19import java.util.HashSet;
20import java.util.Map;
21import java.util.Set;
22
23// Third-party libraries
24import org.apache.commons.logging.Log;
25import org.apache.commons.logging.LogFactory;
26import org.hibernate.Criteria;
27import org.hibernate.FetchMode;
28import org.hibernate.HibernateException;
29import org.hibernate.Session;
30import org.springframework.orm.hibernate3.HibernateCallback;
31
32// Application-internal dependencies
33import ome.parameters.Parameters;
34import static ome.parameters.Parameters.*;
35import ome.parameters.QueryParameter;
36import ome.util.builders.PojoOptions;
37
38/**
39 * base Query type to facilitate the creation of ORM queries. This class
40 * attempts to enforce a strict usage pattern. First, subclasses must define a
41 * {@link ome.services.query.Definitions} instance, which can optionally (and
42 * perhaps preferrably) be static, which must be passed into the super
43 * constructor along with the {@link ome.parameters.Parameters} provided during
44 * lookup.
45 * <p>
46 * Queries can optionally define a {@link #enableFilters(Session)} method
47 * (perhaps using pre-defined filters like
48 * {@link #ownerOrGroupFilters(Session, String[])} to limit the entities
49 * returned.
50 * </p>
51 *
52 * @author Josh Moore, <a href="mailto:josh.moore@gmx.de">josh.moore@gmx.de</a>
53 * @version 1.0 <small> (<b>Internal version:</b> $Rev$ $Date$) </small>
54 * @since OMERO 3.0
55 */
56public abstract class Query<T> implements HibernateCallback {
57    private static Log log = LogFactory.getLog(Query.class);
58
59    // For Criteria
60    /**
61     * imported constant for ease of use
62     *
63     * @see FetchMode#JOIN
64     */
65    protected final static FetchMode FETCH = FetchMode.JOIN;
66
67    /**
68     * imported constant for ease of use
69     *
70     * @see Criteria#LEFT_JOIN
71     */
72    protected final static int LEFT_JOIN = Criteria.LEFT_JOIN;
73
74    /**
75     * imported constant for ease of use
76     *
77     * @see Criteria#INNER_JOIN
78     */
79    protected final static int INNER_JOIN = Criteria.INNER_JOIN;
80
81    /**
82     * container of {@link QueryParameterDef} instances. Typically created
83     * statically in Query subclasses and passed to the
84     * {@link Query#Query(Definitions, Parameters)} constructor
85     */
86    protected final Definitions defs;
87
88    /**
89     * container of {@link QueryParameter} instances. These must at least cover
90     * all the {@link QueryParameterDef}s defined for this {@link Query} but
91     * can define more. Other special fields of {@link Parameters}, such as a
92     * {@link ome.parameters.Filter} instance can also be used by {@link Query}
93     * instances.
94     */
95    protected final Parameters params;
96
97    /**
98     * one of two possible outcomes of the {@link #buildQuery(Session)} method.
99     * If not null on {@link #doInHibernate(Session) execution}, this instance
100     * will be used.
101     *
102     * This field is private so that we can guarantee that subclasses build one
103     * and only one representation.
104     *
105     * @see #_criteria
106     */
107    private org.hibernate.Query _query;
108
109    /**
110     * one of two possible outcomes of the {@link #buildQuery(Session)} method.
111     * If not null on {@link #doInHibernate(Session) execution}, this instance
112     * will be used.
113     *
114     * This field is private so that we can guarantee that subclasses build one
115     * and only one representation.
116     *
117     * @see #_query
118     */
119    private org.hibernate.Criteria _criteria;
120
121    /* have to have the Parameters */
122    private Query() {
123        this.defs = null;
124        this.params = null;
125        checkParameters();
126    }
127
128    /**
129     * main constructor used by subclasses. Both arguments must be provided.
130     *
131     * @param definitions
132     *            Not null.
133     * @param parameters
134     *            Not null.
135     */
136    public Query(Definitions definitions, Parameters parameters) {
137        this.defs = definitions;
138        this.params = parameters;
139        checkParameters();
140    }
141
142    /**
143     * check the {@link Parameters} instance against the {@link Definitions}
144     * instance for this Query. Can be extended by subclasses, but
145     * <code>super.checkParameters()</code> should most likely be called.
146     */
147    protected void checkParameters() {
148
149        if (defs == null) {
150            throw new IllegalStateException(
151                    "Query parameter definitions not set.");
152        }
153
154        if (params == null) {
155            throw new IllegalArgumentException("Null arrays "
156                    + "are not valid for definitions.");
157        }
158
159        Set<String> missing = new HashSet<String>();
160        for (String name : defs.keySet()) {
161            if (!defs.get(name).optional && !params.keySet().contains(name)) {
162                missing.add(name);
163            }
164        }
165
166        if (missing.size() > 0) {
167            throw new IllegalArgumentException(
168                    "Required parameters missing from query: " + missing);
169        }
170
171        for (String name : defs.keySet()) {
172            QueryParameter parameter = params.get(name);
173            QueryParameterDef def = defs.get(name);
174
175            def.errorIfInvalid(parameter);
176
177        }
178
179    }
180
181    // ~ Lookups
182    // =========================================================================
183
184    /**
185     * check that there is a {@link Definitions definition} for this
186     * {@link Query} with the provided argument as its
187     * {@link QueryParameterDef#name name}.
188     */
189    public boolean check(String name) {
190        return defs.containsKey(name);
191    }
192
193    /**
194     * get the {@link QueryParameter} for this name argument.
195     */
196    public QueryParameter get(String name) {
197        return params.get(name);
198    }
199
200    /**
201     * get the Object value for this name argument. Returns null even if no
202     * QueryParameter is associated with the name (no exception).
203     */
204    public Object value(String name) {
205        QueryParameter p = params.get(name);
206        return p == null ? null : p.value;
207    }
208
209    // ~ Execution
210    // =========================================================================
211
212    /**
213     * template method defined by {@link HibernateTemplate}. This does not need
214     * to be overriden by subclasses, but rather {@link #buildQuery(Session)}.
215     * This ensures that the filters are set properly, that
216     * {@link #buildQuery(Session)} does its job, and that everything is cleaned
217     * up properly afterwards.
218     *
219     * It also enforces contracts established by {@link Parameters} and
220     * {@link ome.parameters.Filter}
221     */
222    public Object doInHibernate(Session session) throws HibernateException,
223            SQLException {
224        try {
225            enableFilters(session);
226            buildQuery(session);
227
228            if (_query == null && _criteria == null) {
229                throw new IllegalStateException(
230                        "buildQuery did not properly define a Query or "
231                                + "Criteria\n by calling setQuery() or setCriteria().");
232            }
233
234            boolean unique = params.getFilter().isUnique();
235
236            if (_query != null) {
237                _query.setFirstResult(params.getFilter().firstResult());
238                _query.setMaxResults(params.getFilter().maxResults());
239                return unique ? _query.uniqueResult() : _query.list();
240            } else {
241                _criteria.setFirstResult(params.getFilter().firstResult());
242                _criteria.setMaxResults(params.getFilter().maxResults());
243                return unique ? _criteria.uniqueResult() : _criteria.list();
244            }
245
246        } finally {
247            disableFilters(session);
248        }
249    }
250
251    /**
252     * main point of entry for subclasses. This method must build either a
253     * {@link org.hibernate.Criteria} or a {@link org.hibernate.Query} instance
254     * and make it available via {@link #setCriteria(org.hibernate.Criteria)} or
255     * {@link #setQuery(org.hibernate.Query)}
256     */
257    protected abstract void buildQuery(Session session)
258            throws HibernateException, SQLException;
259
260    /**
261     * provide this Query instance with a {@link org.hibernate.Query} to be used
262     * for retrieving data. {@link #setCriteria(org.hibernate.Criteria)} should
263     * not also be called with a non-null value.
264     */
265    protected void setQuery(org.hibernate.Query query) {
266        if (_criteria != null) {
267            throw new IllegalStateException(
268                    "This Query already has a Criteria set:" + _criteria);
269        }
270        _query = query;
271    }
272
273    /**
274     * provide this Query instance with a {@link org.hibernate.Criteria} to be
275     * used for retrieving data. {@link #setQuery(org.hibernate.Query)} should
276     * not also be called with a non-null value.
277     */
278    protected void setCriteria(org.hibernate.Criteria criteria) {
279        if (_query != null) {
280            throw new IllegalStateException(
281                    "This Query already has a Query set:" + _query);
282        }
283        _criteria = criteria;
284    }
285
286    /**
287     * the set of filters that is being or has been enabled for this Query.
288     */
289    protected Set<String> newlyEnabledFilters = new HashSet<String>();
290
291    /**
292     * does nothing by default, but can be overriden by subclasses to enable
293     * particular filters.
294     */
295    protected void enableFilters(Session session) {
296
297    }
298
299    /**
300     * standard filter used by many subclasses which uses the
301     * {@link PojoOptions#isExperimenter()} and {@link PojoOptions#isGroup()}
302     * booleans to see if a filter should be turned on. If both booleans are
303     * active, group wins. The constant {@link Parameters#OWNER_ID} or
304     * {@link Parameters#GROUP_ID} is then used to define a filter.
305     */
306    protected void ownerOrGroupFilters(Session session, String[] ownerFilters,
307            String[] groupFilters) {
308
309        if (check(OPTIONS)) {
310            PojoOptions po = new PojoOptions((Map) value(OPTIONS));
311
312            if (po.isGroup()) {
313                for (String filter : groupFilters) {
314                    if (session.getEnabledFilter(filter) != null) {
315                        newlyEnabledFilters.add(filter);
316                    }
317
318                    session.enableFilter(filter).setParameter(GROUP_ID,
319                            po.getGroup());
320                }
321            } else if (po.isExperimenter()) {
322                for (String filter : ownerFilters) {
323                    if (session.getEnabledFilter(filter) != null) {
324                        newlyEnabledFilters.add(filter);
325                    }
326
327                    session.enableFilter(filter).setParameter(OWNER_ID,
328                            po.getExperimenter());
329                }
330            }
331
332        }
333    }
334
335    /**
336     * turns the filters off that are listed in {@link #newlyEnabledFilters}
337     */
338    protected void disableFilters(Session session) {
339        for (String enabledFilter : newlyEnabledFilters) {
340            session.disableFilter(enabledFilter);
341        }
342
343    }
344}
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/