source: VirtualCollectionRegistry/tags/VirtualCollectionRegistry-0.4.0-alpha2/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistry.java @ 5557

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

tag for VCR alpha 2

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