source: VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistryImpl.java @ 5616

Last change on this file since 5616 was 5616, checked in by Twan Goosen, 10 years ago

Extracted interface from VirtualCollectionRegistry.
Created test for VirtualCollectionResource? of REST service that uses this interface for mocking.

  • Property svn:eol-style set to native
File size: 28.2 KB
Line 
1package eu.clarin.cmdi.virtualcollectionregistry;
2
3import eu.clarin.cmdi.oai.provider.impl.OAIProvider;
4import eu.clarin.cmdi.virtualcollectionregistry.model.User;
5import eu.clarin.cmdi.virtualcollectionregistry.model.User_;
6import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollection;
7import eu.clarin.cmdi.virtualcollectionregistry.model.VirtualCollectionList;
8import eu.clarin.cmdi.virtualcollectionregistry.pid.PersistentIdentifier;
9import eu.clarin.cmdi.virtualcollectionregistry.pid.PersistentIdentifierProvider;
10import eu.clarin.cmdi.virtualcollectionregistry.query.ParsedQuery;
11import eu.clarin.cmdi.virtualcollectionregistry.service.VirtualCollectionValidator;
12import java.security.Principal;
13import java.util.Date;
14import java.util.List;
15import java.util.concurrent.Executors;
16import java.util.concurrent.ScheduledExecutorService;
17import java.util.concurrent.ThreadFactory;
18import java.util.concurrent.TimeUnit;
19import java.util.concurrent.atomic.AtomicBoolean;
20import java.util.concurrent.atomic.AtomicInteger;
21import javax.persistence.EntityManager;
22import javax.persistence.EntityTransaction;
23import javax.persistence.LockModeType;
24import javax.persistence.NoResultException;
25import javax.persistence.TypedQuery;
26import javax.persistence.criteria.CriteriaBuilder;
27import javax.persistence.criteria.CriteriaQuery;
28import javax.persistence.criteria.Order;
29import javax.persistence.criteria.Predicate;
30import javax.persistence.criteria.Root;
31import org.slf4j.Logger;
32import org.slf4j.LoggerFactory;
33import org.springframework.beans.factory.DisposableBean;
34import org.springframework.beans.factory.InitializingBean;
35import org.springframework.beans.factory.annotation.Autowired;
36import org.springframework.beans.factory.annotation.Qualifier;
37import org.springframework.stereotype.Service;
38
39@Service
40public class VirtualCollectionRegistryImpl implements VirtualCollectionRegistry, InitializingBean, DisposableBean {
41
42    @Autowired
43    private DataStore datastore; //TODO: replace with Spring managed EM?
44    @Autowired
45    private PersistentIdentifierProvider pid_provider;
46    @Autowired
47    private OAIProvider oaiProvider;
48    @Autowired
49    @Qualifier("creation")
50    private VirtualCollectionValidator validator;
51    @Autowired
52    private AdminUsersService adminUsersService;
53
54    private static final Logger logger
55            = LoggerFactory.getLogger(VirtualCollectionRegistryImpl.class);
56    private final AtomicBoolean intialized = new AtomicBoolean(false);
57    /**
58     * Scheduled executor service for the maintenance check
59     *
60     * @see #maintenance(long)
61     */
62    private final ScheduledExecutorService maintenanceExecutor
63            = createSingleThreadScheduledExecutor("VirtualCollectionRegistry-Maintenance");
64
65    @Override
66    public void afterPropertiesSet() throws VirtualCollectionRegistryException {
67        // called by Spring directly after Bean construction
68        doInitalize();
69    }
70
71    private void doInitalize() throws VirtualCollectionRegistryException {
72        if (intialized.get()) {
73            throw new VirtualCollectionRegistryException("already initialized");
74        }
75        logger.info("Initializing virtual collection registry ...");
76        try {
77            maintenanceExecutor.scheduleWithFixedDelay(new Runnable() {
78
79                @Override
80                public void run() {
81                    maintenance(new Date().getTime());
82                }
83            }, 60, 60, TimeUnit.SECONDS);
84            this.intialized.set(true);
85            logger.info("virtual collection registry successfully intialized");
86        } catch (RuntimeException e) {
87            logger.error("error initalizing virtual collection registry", e);
88            throw e;
89        }
90    }
91
92    @Override
93    public void destroy() throws VirtualCollectionRegistryException, InterruptedException {
94        logger.info("Stopping Virtual Collection Registry maintenance schedule");
95        maintenanceExecutor.shutdown();
96        if (!maintenanceExecutor.awaitTermination(60, TimeUnit.SECONDS)) {
97            logger.warn("Timeout while waiting for maintenance thread to terminate, will try to shut down");
98        }
99
100        logger.info("Shutting down OAI provider");
101        oaiProvider.shutdown();
102    }
103
104    /**
105     * Will store the specified collection; it will also set the owner according
106     * to the specified principal and set its state to
107     * {@link VirtualCollection.State#PRIVATE}
108     *
109     * @param principal owner principal
110     * @param vc collection to store
111     * @return identifier of the persisted collection
112     * @throws VirtualCollectionRegistryException
113     */
114    public long createVirtualCollection(Principal principal,
115            VirtualCollection vc) throws VirtualCollectionRegistryException {
116        if (principal == null) {
117            throw new NullPointerException("principal == null");
118        }
119        if (vc == null) {
120            throw new NullPointerException("vc == null");
121        }
122
123        logger.debug("creating virtual collection");
124
125        validator.validate(vc);
126        try {
127            EntityManager em = datastore.getEntityManager();
128            em.getTransaction().begin();
129
130            // fetch user, if user does not exist create new
131            User user = fetchUser(em, principal);
132            if (user == null) {
133                user = new User(principal.getName());
134                em.persist(user);
135            }
136            vc.setOwner(user);
137
138            // force new collection to be private
139            vc.setState(VirtualCollection.State.PRIVATE);
140
141            // store virtual collection
142            logger.debug("persisting new virtual collection", vc.getId());
143            em.persist(vc);
144            em.getTransaction().commit();
145            logger.debug("virtual collection created (id={})", vc.getId());
146            return vc.getId();
147        } catch (Exception e) {
148            logger.error("error while creating virtual collection", e);
149            throw new VirtualCollectionRegistryException(
150                    "error while creating virtual collection", e);
151        }
152    }
153
154    public long updateVirtualCollection(Principal principal, long id,
155            VirtualCollection vc) throws VirtualCollectionRegistryException {
156        if (principal == null) {
157            throw new NullPointerException("principal == null");
158        }
159        if (id <= 0) {
160            throw new IllegalArgumentException("id <= 0");
161        }
162        if (vc == null) {
163            throw new NullPointerException("vc == null");
164        }
165
166        logger.debug("updating virtual collection (id={})", id);
167
168        validator.validate(vc);
169
170        try {
171            EntityManager em = datastore.getEntityManager();
172            em.getTransaction().begin();
173            VirtualCollection c = em.find(VirtualCollection.class,
174                    Long.valueOf(id), LockModeType.PESSIMISTIC_WRITE);
175            /*
176             * Do not check for deleted state here, as we might want to
177             * resurrect deleted virtual collections.
178             */
179            if (c == null) {
180                logger.debug("virtual collection (id={}) not found", id);
181                throw new VirtualCollectionNotFoundException(id);
182            }
183            if (!isAllowedToModify(principal, c)) {
184                throw new VirtualCollectionRegistryPermissionException(
185                        "permission denied for user \""
186                        + principal.getName() + "\"");
187            }
188
189            // update virtual collection
190            c.updateFrom(vc);
191
192            validator.validate(c);
193            em.merge(c);
194            em.getTransaction().commit();
195            logger.debug("updated virtual collection (id={})", vc.getId());
196            return c.getId();
197        } catch (VirtualCollectionRegistryException e) {
198            logger.warn("failed updating virtual collecion (id={}): {}", id,
199                    e.getMessage());
200            throw e;
201        } catch (Exception e) {
202            logger.error("error while updating virtual collection", e);
203            throw new VirtualCollectionRegistryException(
204                    "error while updating virtual collection", e);
205        }
206    }
207
208    public long deleteVirtualCollection(Principal principal, long id)
209            throws VirtualCollectionRegistryException {
210        if (principal == null) {
211            throw new NullPointerException("principal == null");
212        }
213        if (id <= 0) {
214            throw new IllegalArgumentException("id <= 0");
215        }
216
217        logger.debug("deleting virtual collection (id={})", id);
218
219        try {
220            EntityManager em = datastore.getEntityManager();
221            em.getTransaction().begin();
222            VirtualCollection vc = em.find(VirtualCollection.class,
223                    Long.valueOf(id), LockModeType.PESSIMISTIC_WRITE);
224            if ((vc == null) || vc.isDeleted()) {
225                logger.debug("virtual collection (id={}) not found", id);
226                throw new VirtualCollectionNotFoundException(id);
227            }
228            if (!isAllowedToModify(principal, vc)) {
229                logger.debug("virtual collection (id={}) not owned by "
230                        + "user '{}'", id, principal.getName());
231                throw new VirtualCollectionRegistryPermissionException(
232                        "permission denied for user \""
233                        + principal.getName() + "\"");
234            }
235            if (!vc.isPrivate()) {
236                logger.debug("virtual collection (id={}) cannot be "
237                        + "deleted (invalid state)", id);
238                throw new VirtualCollectionRegistryPermissionException(
239                        "virtual collection cannot be deleted");
240            }
241            vc.setState(VirtualCollection.State.DELETED);
242            em.getTransaction().commit();
243            return vc.getId();
244        } catch (VirtualCollectionRegistryException e) {
245            logger.debug("failed deleting virtual collecion (id={}): {}", id,
246                    e.getMessage());
247            throw e;
248        } catch (Exception e) {
249            logger.error("error while deleting virtual collection", e);
250            throw new VirtualCollectionRegistryException(
251                    "error while deleting virtual collection", e);
252        }
253    }
254
255    public VirtualCollection.State getVirtualCollectionState(long id)
256            throws VirtualCollectionRegistryException {
257        if (id <= 0) {
258            throw new IllegalArgumentException("id <= 0");
259        }
260
261        logger.debug("retrieve virtual collection state (id={})", id);
262
263        try {
264            EntityManager em = datastore.getEntityManager();
265            em.getTransaction().begin();
266            VirtualCollection vc
267                    = em.find(VirtualCollection.class, Long.valueOf(id));
268            em.getTransaction().commit();
269            if ((vc == null) || vc.isDeleted()) {
270                logger.debug("virtual collection (id={}) not found", id);
271                throw new VirtualCollectionNotFoundException(id);
272            }
273            return vc.getState();
274        } catch (VirtualCollectionRegistryException e) {
275            throw e;
276        } catch (Exception e) {
277            logger.error(
278                    "error while retrieving state of virtual collection", e);
279            throw new VirtualCollectionRegistryException(
280                    "error while retrieving state of virtual collection", e);
281        }
282    }
283
284    public void setVirtualCollectionState(Principal principal, long id,
285            VirtualCollection.State state)
286            throws VirtualCollectionRegistryException {
287        if (principal == null) {
288            throw new NullPointerException("principal == null");
289        }
290        if (id <= 0) {
291            throw new IllegalArgumentException("id <= 0");
292        }
293        if (state == null) {
294            throw new NullPointerException("state == null");
295        }
296        if ((state != VirtualCollection.State.PUBLIC_PENDING)
297                && (state != VirtualCollection.State.PRIVATE)) {
298            throw new IllegalArgumentException(
299                    "only PUBLIC_PENDING or PRIVATE are allowed");
300        }
301
302        logger.debug("setting state virtual collection state (id={}) to '{}'",
303                id, state);
304
305        try {
306            EntityManager em = datastore.getEntityManager();
307            em.getTransaction().begin();
308            VirtualCollection vc = em.find(VirtualCollection.class,
309                    Long.valueOf(id), LockModeType.PESSIMISTIC_WRITE);
310            if ((vc == null) || vc.isDeleted()) {
311                logger.debug("virtual collection (id={}) not found", id);
312                throw new VirtualCollectionNotFoundException(id);
313            }
314            if (!isAllowedToModify(principal, vc)) {
315                logger.debug("virtual collection (id={}) not owned by "
316                        + "user '{}'", id, principal.getName());
317                throw new VirtualCollectionRegistryPermissionException(
318                        "permission denied for user \""
319                        + principal.getName() + "\"");
320            }
321
322            /*
323             * XXX: deny update from public to private?
324             */
325            boolean update = false;
326            switch (state) {
327                case PRIVATE:
328                    update = vc.getState() != state;
329                    break;
330                case PUBLIC_PENDING:
331                    update = vc.getState() != VirtualCollection.State.PUBLIC;
332                    break;
333                default:
334                    /* silence warning; update will stay false */
335                    break;
336            }
337            if (update) {
338                vc.setState(state);
339                em.persist(vc);
340            }
341            em.getTransaction().commit();
342        } catch (VirtualCollectionRegistryException e) {
343            throw e;
344        } catch (Exception e) {
345            logger.error(
346                    "error while setting state of virtual collection", e);
347            throw new VirtualCollectionRegistryException(
348                    "error while setting state of virtual collection", e);
349        }
350    }
351
352    /**
353     *
354     * @param id identifier of the virtual collection to retrieve
355     * @return the identified virtual collection, never null
356     * @throws VirtualCollectionRegistryException if no virtual collection with
357     * the specified identifier exists
358     */
359    public VirtualCollection retrieveVirtualCollection(long id)
360            throws VirtualCollectionRegistryException {
361        if (id <= 0) {
362            throw new IllegalArgumentException("id <= 0");
363        }
364
365        logger.debug("retrieve virtual collection (id={})", id);
366
367        try {
368            EntityManager em = datastore.getEntityManager();
369            em.getTransaction().begin();
370            VirtualCollection vc
371                    = em.find(VirtualCollection.class, Long.valueOf(id));
372            em.getTransaction().commit();
373            if ((vc == null) || vc.isDeleted()) {
374                logger.debug("virtual collection (id={}) not found", id);
375                throw new VirtualCollectionNotFoundException(id);
376            }
377            logger.debug("virtual collection retrieved (id={})", id);
378            return vc;
379        } catch (VirtualCollectionRegistryException e) {
380            throw e;
381        } catch (Exception e) {
382            logger.error("error while retrieving virtual collection", e);
383            throw new VirtualCollectionRegistryException(
384                    "error while retrieving virtual collection", e);
385        }
386    }
387
388    public VirtualCollectionList getVirtualCollections(String query,
389            int offset, int count) throws VirtualCollectionRegistryException {
390        EntityManager em = datastore.getEntityManager();
391        try {
392            em.getTransaction().begin();
393
394            // setup queries
395            TypedQuery<Long> cq = null;
396            TypedQuery<VirtualCollection> q = null;
397            if (query != null) {
398                ParsedQuery parsedQuery = ParsedQuery.parseQuery(query);
399                if (logger.isDebugEnabled()) {
400                    logger.debug(parsedQuery.getPrettyPrinted());
401                }
402                cq = parsedQuery.getCountQuery(em, null, VirtualCollection.State.PUBLIC);
403                q = parsedQuery.getQuery(em, null, VirtualCollection.State.PUBLIC);
404            } else {
405                cq = em.createNamedQuery("VirtualCollection.countAllPublic",
406                        Long.class);
407                q = em.createNamedQuery("VirtualCollection.findAllPublic",
408                        VirtualCollection.class);
409            }
410
411            // commence query ...
412            List<VirtualCollection> results = null;
413            long totalCount = cq.getSingleResult();
414
415            // optimization; don't query, if we won't get any results
416            /*
417             *  FIXME: offset == -1 is temporary hack for just fetching
418             *  total count; re-factor to have fetch-count and fetch-data
419             *  methods!
420             */
421            if ((totalCount > 0) && (offset > -1)) {
422                if (offset > 0) {
423                    q.setFirstResult(offset);
424                }
425                if (count > 0) {
426                    q.setMaxResults(count);
427                }
428                results = q.getResultList();
429            }
430            return new VirtualCollectionList(results, offset, (int) totalCount);
431        } catch (Exception e) {
432            logger.error("error while enumerating virtual collections", e);
433            throw new VirtualCollectionRegistryException(
434                    "error while enumerating virtual collections", e);
435        } finally {
436            EntityTransaction tx = em.getTransaction();
437            if ((tx != null) && !tx.getRollbackOnly()) {
438                tx.commit();
439            }
440        }
441    }
442
443    public VirtualCollectionList getVirtualCollections(Principal principal,
444            String query, int offset, int count)
445            throws VirtualCollectionRegistryException {
446        if (principal == null) {
447            throw new NullPointerException("principal == null");
448        }
449        EntityManager em = datastore.getEntityManager();
450        try {
451            List<VirtualCollection> results = null;
452            long totalCount = 0;
453
454            em.getTransaction().begin();
455
456            /*
457             * fetch user. if user is not found, he has not yet registered any
458             * virtual collections, so just return an empty list
459             */
460            User user = fetchUser(em, principal);
461            if (user != null) {
462                // setup queries
463                TypedQuery<Long> cq = null;
464                TypedQuery<VirtualCollection> q = null;
465                if (query != null) {
466                    ParsedQuery parsedQuery = ParsedQuery.parseQuery(query);
467                    if (logger.isDebugEnabled()) {
468                        logger.debug(parsedQuery.getPrettyPrinted());
469                    }
470                    cq = parsedQuery.getCountQuery(em, user, null);
471                    q = parsedQuery.getQuery(em, user, null);
472                } else {
473                    cq = em.createNamedQuery("VirtualCollection.countByOwner",
474                            Long.class);
475                    cq.setParameter("owner", user);
476                    q = em.createNamedQuery("VirtualCollection.findByOwner",
477                            VirtualCollection.class);
478                    q.setParameter("owner", user);
479                }
480
481                // commence query ...
482                totalCount = cq.getSingleResult();
483
484                // optimization; don't query, if we won't get any results
485                /*
486                 *  FIXME: offset == -1 is temporary hack for just fetching
487                 *  total count; re-factor to have fetch-count and fetch-data
488                 *  methods!
489                 */
490                if ((totalCount > 0) && (offset > -1)) {
491                    if (offset > 0) {
492                        q.setFirstResult(offset);
493                    }
494                    if (count > 0) {
495                        q.setMaxResults(count);
496                    }
497                    results = q.getResultList();
498                }
499            }
500            return new VirtualCollectionList(results, offset, (int) totalCount);
501        } catch (Exception e) {
502            logger.error("error while enumerating virtual collections", e);
503            throw new VirtualCollectionRegistryException(
504                    "error while enumerating virtual collections", e);
505        } finally {
506            EntityTransaction tx = em.getTransaction();
507            if ((tx != null) && !tx.getRollbackOnly()) {
508                tx.commit();
509            }
510        }
511    }
512
513    public int getVirtualCollectionCount(QueryOptions options)
514            throws VirtualCollectionRegistryException {
515        logger.trace("Getting virtual collection count");
516        EntityManager em = datastore.getEntityManager();
517        try {
518            CriteriaBuilder cb = em.getCriteriaBuilder();
519            CriteriaQuery<Long> cq = cb.createQuery(Long.class);
520            Root<VirtualCollection> root = cq.from(VirtualCollection.class);
521            if (options != null) {
522                Predicate where = options.getWhere(cb, cq, root);
523                if (where != null) {
524                    cq.where(where);
525                }
526            }
527            em.getTransaction().begin();
528            TypedQuery<Long> query
529                    = em.createQuery(cq.select(cb.count(root)));
530            final long count = query.getSingleResult();
531            if (count >= Integer.MAX_VALUE) {
532                throw new VirtualCollectionRegistryException(
533                        "resultset too large");
534            }
535            logger.trace("Counted {} collections", count);
536            return (int) count;
537        } catch (Exception e) {
538            logger.error("error while counting virtual collections", e);
539            throw new VirtualCollectionRegistryException(
540                    "error while counting virtual collections", e);
541        } finally {
542            EntityTransaction tx = em.getTransaction();
543            if ((tx != null) && tx.isActive() && !tx.getRollbackOnly()) {
544                tx.commit();
545            }
546        }
547    }
548
549    public List<User> getUsers() {
550        final EntityManager em = datastore.getEntityManager();
551        try {
552            final CriteriaBuilder cb = em.getCriteriaBuilder();
553            final CriteriaQuery<User> cq = cb.createQuery(User.class);
554            final Root<User> root = cq.from(User.class);
555
556            // select all users, sort by display name then name
557            cq.select(root);
558            cq.orderBy(
559                    cb.asc(root.get(User_.displayName)),
560                    cb.asc(root.get(User_.name)));
561
562            em.getTransaction().begin();
563            final TypedQuery<User> query = em.createQuery(cq);
564            return query.getResultList();
565        } finally {
566            EntityTransaction tx = em.getTransaction();
567            if ((tx != null) && tx.isActive() && !tx.getRollbackOnly()) {
568                tx.commit();
569            }
570        }
571    }
572
573    public List<VirtualCollection> getVirtualCollections(
574            int first, int count, QueryOptions options)
575            throws VirtualCollectionRegistryException {
576        EntityManager em = datastore.getEntityManager();
577        try {
578            CriteriaBuilder cb = em.getCriteriaBuilder();
579            CriteriaQuery<VirtualCollection> cq
580                    = cb.createQuery(VirtualCollection.class);
581            Root<VirtualCollection> root = cq.from(VirtualCollection.class);
582            if (options != null) {
583                final Predicate where = options.getWhere(cb, cq, root);
584                if (where != null) {
585                    cq.where(where);
586                }
587                final Order[] order = options.getOrderBy(cb, root);
588                if (order != null) {
589                    cq.orderBy(order);
590                }
591            }
592            em.getTransaction().begin();
593            TypedQuery<VirtualCollection> query
594                    = em.createQuery(cq.select(root));
595            if (first > -1) {
596                query.setFirstResult(first);
597            }
598            if (count > 0) {
599                query.setMaxResults(count);
600            }
601            return query.getResultList();
602        } catch (Exception e) {
603            logger.error("error while fetching virtual collections", e);
604            throw new VirtualCollectionRegistryException(
605                    "error while fetching virtual collections", e);
606        } finally {
607            EntityTransaction tx = em.getTransaction();
608            if ((tx != null) && tx.isActive() && !tx.getRollbackOnly()) {
609                tx.commit();
610            }
611        }
612    }
613
614    private void maintenance(long now) {
615        logger.debug("Maintenance check");
616        // allocate persistent identifier roughly after 30 seconds
617        final Date nowDateAlloc = new Date(now - 30 * 1000);
618        // (for now) purge deleted collection roughly after 30 seconds
619        final Date nowDatePurge = new Date(now - 30 * 1000);
620
621        EntityManager em = datastore.getEntityManager();
622        try {
623            /*
624             * delayed allocation of persistent identifier
625             */
626            em.getTransaction().begin();
627            TypedQuery<VirtualCollection> q
628                    = em.createNamedQuery("VirtualCollection.findAllByState",
629                            VirtualCollection.class);
630            q.setParameter("state", VirtualCollection.State.PUBLIC_PENDING);
631            q.setParameter("date", nowDateAlloc);
632            q.setLockMode(LockModeType.PESSIMISTIC_WRITE);
633            for (VirtualCollection vc : q.getResultList()) {
634                if (vc.getPersistentIdentifier() == null) {
635                    PersistentIdentifier pid = pid_provider.createIdentifier(vc);
636                    vc.setPersistentIdentifier(pid);
637                }
638                vc.setState(VirtualCollection.State.PUBLIC);
639                em.persist(vc);
640                logger.info("assigned pid (identifer='{}') to virtual"
641                        + "collection (id={})",
642                        vc.getPersistentIdentifier().getIdentifier(),
643                        vc.getId());
644            }
645            em.getTransaction().commit();
646
647            /*
648             * delayed purging of deleted virtual collections
649             */
650            em.getTransaction().begin();
651            q.setParameter("state", VirtualCollection.State.DELETED);
652            q.setParameter("date", nowDatePurge);
653            q.setLockMode(LockModeType.PESSIMISTIC_WRITE);
654            for (VirtualCollection vc : q.getResultList()) {
655                vc.setState(VirtualCollection.State.DEAD);
656                em.remove(vc);
657                logger.debug("purged virtual collection (id={})", vc.getId());
658            }
659            em.getTransaction().commit();
660        } catch (VirtualCollectionRegistryException e) {
661            logger.error("error while doing maintenance", e);
662        } finally {
663            datastore.closeEntityManager();
664        }
665    }
666
667    private static User fetchUser(EntityManager em, Principal principal) {
668        User user = null;
669        try {
670            TypedQuery<User> q
671                    = em.createNamedQuery("User.findByName", User.class);
672            q.setParameter("name", principal.getName());
673            user = q.getSingleResult();
674        } catch (NoResultException e) {
675            /* IGNORE */
676        }
677        return user;
678    }
679
680    /**
681     * Creates a single thread scheduled executor with the specified thread name
682     *
683     * @param threadName name for new executor threads
684     * @return
685     */
686    private static ScheduledExecutorService createSingleThreadScheduledExecutor(final String threadName) {
687        return Executors.newSingleThreadScheduledExecutor(new ThreadFactory() {
688            // decorate default thread factory so that we can provide a
689            // custom thread name
690            final AtomicInteger i = new AtomicInteger(0);
691
692            @Override
693            public Thread newThread(Runnable r) {
694                final Thread thread = Executors.defaultThreadFactory().newThread(r);
695                thread.setName(threadName + "-" + i.addAndGet(1));
696                return thread;
697            }
698        });
699    }
700
701    private boolean isAllowedToModify(Principal principal, VirtualCollection c) {
702        // admin and owner are allowed to modify collections
703        return adminUsersService.isAdmin(principal.getName())
704                || c.getOwner().equalsPrincipal(principal);
705    }
706
707} // class VirtualCollectionRegistry
Note: See TracBrowser for help on using the repository browser.