source: VirtualCollectionRegistry/branches/VirtualCollectionRegistry-1.0-beta/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistry.java @ 5596

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

created a branch for VCR 1.0-beta. Trunk now 1.1-SNAPSHOT

  • 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 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    /**
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.