Changeset 509


Ignore:
Timestamp:
06/15/10 18:40:09 (14 years ago)
Author:
oschonef
Message:
  • delayed purging of deleted virtual collections
  • deny deleting public virtual collections
  • add some JPA locking
  • re-work relations between entities
Location:
VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/VirtualCollectionRegistry.java

    r507 r509  
    33import java.security.Principal;
    44import java.util.Collections;
     5import java.util.Date;
    56import java.util.List;
    67import java.util.Map;
     
    1011
    1112import javax.persistence.EntityManager;
    12 import javax.persistence.EntityTransaction;
     13import javax.persistence.LockModeType;
    1314import javax.persistence.NoResultException;
     15import javax.persistence.PersistenceException;
    1416import javax.persistence.TypedQuery;
    1517
     
    7375                @Override
    7476                public void run() {
    75                     assignPersistentId();
    76                 }
    77             }, 60000, 60000);
     77                    maintenance(this.scheduledExecutionTime());
     78                }
     79            }, 1000, 1000);
    7880            this.intialized.set(true);
    7981            logger.info("virtual collection registry successfully intialized");
     
    189191                        principal.getName() + "\"");
    190192            }
     193            em.lock(c, LockModeType.WRITE);
    191194            c.updateFrom(vc);
    192195            validator.validate(c);
     
    227230            }
    228231            if (!vc.getOwner().equalsPrincipal(principal)) {
     232                logger.debug("virtual collection (id={}) not owned by " +
     233                        "user '{}'", id, principal.getName());
    229234                throw new VirtualCollectionRegistryPermissionException(
    230                         "permission denied for user \"" + principal.getName() +
    231                                 "\"");
    232             }
    233             em.remove(vc);
     235                        "permission denied for user \"" +
     236                        principal.getName() + "\"");
     237            }
     238            if (vc.getState() != VirtualCollection.State.PRIVATE) {
     239                logger.debug("virtual collection (id={}) cannot be " +
     240                        "deleted (invalid state)", id);
     241                throw new VirtualCollectionRegistryPermissionException(
     242                        "virtual collection cannot be deleted");
     243            }
     244            em.lock(vc, LockModeType.WRITE);
     245            vc.setState(VirtualCollection.State.DELETED);
    234246            em.getTransaction().commit();
    235247            return vc.getId();
     
    267279        } catch (VirtualCollectionRegistryException e) {
    268280            throw e;
    269         } catch (Exception e) {
    270             logger.error("error while retrieving virtual collection", e);
    271             throw new VirtualCollectionRegistryException(
    272                     "error while retrieving virtual collection", e);
    273         }
    274     }
    275 
    276     /*
    277      * FIXME: following method is broken, due to pid/uuid changes
    278      */
    279     public VirtualCollection retrieveVirtualCollection(String uuid)
    280             throws VirtualCollectionRegistryException {
    281         if (uuid == null) {
    282             throw new NullPointerException("uuid == null");
    283         }
    284         uuid = uuid.trim();
    285         if (uuid.isEmpty()) {
    286             throw new IllegalArgumentException("uuid is empty");
    287         }
    288 
    289         logger.debug("retrieve virtual collection (uuid={})", uuid);
    290 
    291         try {
    292             EntityManager em = datastore.getEntityManager();
    293             em.getTransaction().begin();
    294             TypedQuery<VirtualCollection> q =
    295                 em.createNamedQuery("VirtualCollection.byUUID",
    296                                     VirtualCollection.class);
    297             q.setParameter("uuid", uuid);
    298             VirtualCollection vc = q.getSingleResult();
    299             em.getTransaction().commit();
    300             return vc;
    301         } catch (NoResultException e) {
    302             logger.debug("virtual collection (uuid={}) not found", uuid);
    303             throw new VirtualCollectionNotFoundException(uuid);
    304281        } catch (Exception e) {
    305282            logger.error("error while retrieving virtual collection", e);
     
    419396    }
    420397
    421     private void assignPersistentId() {
     398    private void maintenance(long now) {
     399        final Date nowDateAlloc = new Date(now - 30*1000);
     400        final Date nowDatePurge = new Date(now - 30*1000);
     401       
    422402        EntityManager em = datastore.getEntityManager();
    423         em.getTransaction().begin();
    424         try {
     403        try {
     404            /*
     405             * delayed allocation of persistent identifier
     406             */
     407            em.getTransaction().begin();
    425408            TypedQuery<VirtualCollection> q =
    426                 em.createNamedQuery("VirtualCollection.findAllInit",
     409                em.createNamedQuery("VirtualCollection.findAllByState",
    427410                                    VirtualCollection.class);
     411            q.setParameter("state", VirtualCollection.State.PUBLIC_PENDING);
     412            q.setParameter("date", nowDateAlloc);
    428413            for (VirtualCollection vc : q.getResultList()) {
    429                 if (vc.getState() != VirtualCollection.State.INIT) {
     414                try {
     415                    em.lock(vc, LockModeType.WRITE);
     416                } catch (PersistenceException e) {
     417                    logger.debug("error locking virtual collection (vc={})", vc.getId());
    430418                    continue;
    431419                }
    432420                PersistentIdentifier pid = pid_provider.createIdentifier(vc);
    433421                vc.setPersistentIdentifier(pid);
    434                 vc.setState(VirtualCollection.State.PRIVATE);
     422                vc.setState(VirtualCollection.State.PUBLIC);
    435423                em.persist(vc);
    436424                logger.debug("assigned pid (identifer='{}') to virtual" +
    437                         "collection (id={})", pid.getIdentifier(), vc.getId());
    438             }
    439             em.getTransaction().commit();
    440         } catch (Exception e) {
    441             logger.error("error while assigning persistent identifier", e);
    442             EntityTransaction tx = em.getTransaction();
    443             if (tx.isActive()) {
    444                 em.getTransaction().rollback();
    445             }
     425                        "collection (id={})",
     426                        vc.getPersistentIdentifier().getIdentifier(),
     427                        vc.getId());
     428            }
     429            em.getTransaction().commit();
     430           
     431            /*
     432             * delayed purging of deleted virtual collections
     433             */
     434            em.getTransaction().begin();
     435            q.setParameter("state", VirtualCollection.State.DELETED);
     436            q.setParameter("date", nowDatePurge);
     437            for (VirtualCollection vc : q.getResultList()) {
     438                try {
     439                    em.lock(vc, LockModeType.WRITE);
     440                } catch (PersistenceException e) {
     441                    logger.debug("error locking virtual collection (vc={})", vc.getId());
     442                    continue;
     443                }
     444                vc.setState(VirtualCollection.State.DEAD);
     445                em.remove(vc);
     446                logger.debug("purged virtual collection (id={})", vc.getId());
     447            }
     448            em.getTransaction().commit();
     449        } catch (Exception e) {
     450            logger.error("error while doing maintenance", e);
     451        } finally {
     452            datastore.closeEntityManager();
    446453        }
    447454    }
  • VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/PersistentIdentifier.java

    r503 r509  
    11package eu.clarin.cmdi.virtualcollectionregistry.model;
    2 
    3 import java.util.Date;
    42
    53import javax.persistence.Column;
     
    75import javax.persistence.EnumType;
    86import javax.persistence.Enumerated;
    9 import javax.persistence.FetchType;
    107import javax.persistence.GeneratedValue;
    118import javax.persistence.GenerationType;
    129import javax.persistence.Id;
    1310import javax.persistence.OneToOne;
     11import javax.persistence.PrimaryKeyJoinColumn;
    1412import javax.persistence.Table;
    15 import javax.persistence.Temporal;
    16 import javax.persistence.TemporalType;
    17 import javax.persistence.Version;
     13
     14import org.apache.commons.lang.NullArgumentException;
    1815
    1916@Entity
     
    2623    @Id
    2724    @GeneratedValue(strategy = GenerationType.AUTO)
    28     @Column(name = "id")
     25    @Column(name = "id", nullable = false)
    2926    private long id = -1;
    30     @OneToOne(fetch = FetchType.EAGER,
    31               optional = false)
    32     private VirtualCollection collection;
     27    @OneToOne(optional = false)
     28    @PrimaryKeyJoinColumn
     29    private VirtualCollection vc;
    3330    @Column(name = "type")
    3431    @Enumerated(EnumType.ORDINAL)
     
    3633    @Column(name = "identifier",
    3734            nullable = false,
    38             updatable = false,
    3935            unique = true)
    4036    private String identifier;
    41     @Column(name = "last_modified",
    42             nullable = false)
    43     @Temporal(TemporalType.TIMESTAMP)
    44     @Version
    45     private Date lastModifed;
    4637
    4738    private PersistentIdentifier() {
    4839    }
    4940
    50     PersistentIdentifier(VirtualCollection collection, Type type,
    51             String identifier) {
     41    PersistentIdentifier(VirtualCollection vc, Type type, String identifier) {
    5242        this();
    53         if (collection == null) {
    54             throw new NullPointerException("collection == null");
     43        if (vc == null) {
     44            throw new NullArgumentException("vc == null");
    5545        }
    5646        if (type == null) {
     
    6454            throw new IllegalArgumentException("identifier is empty");
    6555        }
    66         this.collection = collection;
     56        this.vc = vc;
    6757        this.type = type;
    6858        this.identifier = identifier;
     
    7464
    7565    public VirtualCollection getVirtualCollection() {
    76         return collection;
     66        return vc;
    7767    }
    7868
     
    8373    public String getIdentifier() {
    8474        return identifier;
    85     }
    86 
    87     public Date getLastModified() {
    88         return lastModifed;
    8975    }
    9076
  • VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/Resource.java

    r503 r509  
    2626    @GeneratedValue(strategy = GenerationType.AUTO)
    2727    @Column(name = "id",
    28             nullable = false,
    29             updatable = false,
    30             insertable = true)
     28            nullable = false)
    3129    private long id = -1;
    3230    @Column(name = "type",
  • VirtualCollectionRegistry/trunk/VirtualCollectionRegistry/src/main/java/eu/clarin/cmdi/virtualcollectionregistry/model/VirtualCollection.java

    r507 r509  
    5252                            "WHERE c.state = eu.clarin.cmdi." +
    5353                            "virtualcollectionregistry.model." +
    54                             "VirtualCollection$State.PUBLIC"),
     54                            "VirtualCollection$State.PUBLIC " +
     55                            "ORDER BY c.id"),
    5556        @NamedQuery(name = "VirtualCollection.countAllPublic",
    5657                    query = "SELECT COUNT(c) FROM VirtualCollection c " +
     
    6061        @NamedQuery(name = "VirtualCollection.findByOwner",
    6162                    query = "SELECT c FROM VirtualCollection c " +
    62                             "WHERE c.owner = :owner"),
     63                            "WHERE c.owner = :owner ORDER BY c.id"),
    6364        @NamedQuery(name = "VirtualCollection.countByOwner",
    6465                    query = "SELECT COUNT(c) FROM VirtualCollection c " +
    6566                            "WHERE c.owner = :owner"),
    66         @NamedQuery(name = "VirtualCollection.findAllInit",
     67        @NamedQuery(name = "VirtualCollection.findAllByState",
    6768                    query = "SELECT c FROM VirtualCollection c " +
    68                             "WHERE c.state = eu.clarin.cmdi." +
    69                             "virtualcollectionregistry.model." +
    70                             "VirtualCollection$State.INIT")
     69                            "WHERE c.state = :state AND c.modifedDate < :date")
    7170})
    7271@XmlRootElement(name = "VirtualCollection")
     
    8180    @XmlEnum(String.class)
    8281    public static enum State {
     82        @XmlEnumValue("private")
     83        PRIVATE,
     84        @XmlEnumValue("public-pending")
     85        PUBLIC_PENDING,
     86        @XmlEnumValue("public")
     87        PUBLIC,
    8388        @XmlEnumValue("deleted")
    8489        DELETED,
    85         @XmlEnumValue("initialized")
    86         INIT,
    87         @XmlEnumValue("public")
    88         PUBLIC,
    89         @XmlEnumValue("private")
    90         PRIVATE
     90        @XmlEnumValue("dead")
     91        DEAD
    9192    } // enum State
    9293    @XmlType(namespace = "urn:x-vcr:virtualcollection:visibility")
     
    120121            nullable = false)
    121122    @Enumerated(EnumType.ORDINAL)
    122     private State state = State.INIT;
    123     @OneToOne(cascade = { CascadeType.PERSIST,
    124                           CascadeType.REFRESH,
    125                           CascadeType.MERGE },
     123    private State state = State.PRIVATE;
     124    @OneToOne(optional = true,
     125              orphanRemoval = true,
     126              cascade = CascadeType.ALL,
    126127              fetch = FetchType.EAGER,
    127               orphanRemoval = true,
    128               optional = true,
    129               mappedBy = "collection")
     128              mappedBy = "vc")
    130129    private PersistentIdentifier pid;
    131130    @Column(name = "name",
     
    148147    private Creator creator;
    149148    @OneToMany(cascade = CascadeType.ALL,
    150                fetch = FetchType.LAZY,
    151                orphanRemoval = true)
     149               fetch = FetchType.LAZY)
    152150    @JoinColumn(name = "vc_id",
    153151                nullable = false)
     
    174172            throw new NullPointerException("state == null");
    175173        }
    176         boolean valid;
    177         switch (this.state) {
    178         case INIT:
    179             valid = (state == State.PRIVATE);
    180             break;
    181         case PRIVATE:
    182             valid = (state == State.PUBLIC) || (state == State.DELETED);
    183             break;
    184         default:
    185             valid = false;
    186         } // switch
    187         if (valid) {
    188             this.state = state;
    189         } else {
    190             throw new IllegalStateException("invalid transition from " +
    191                     this.state + " to " + state);
     174        if (this.state != state) {
     175            boolean valid = false;
     176            switch (this.state) {
     177            case PRIVATE:
     178                valid = (state == State.PUBLIC) || (state == State.DELETED);
     179                break;
     180            case DELETED:
     181                valid = (state == State.PRIVATE) || (state == State.DEAD);
     182                break;
     183            default:
     184                /* NOTHING */
     185            } // switch
     186            if (valid) {
     187                this.state = state;
     188            } else {
     189                throw new IllegalStateException("invalid transition from " +
     190                        this.state + " to " + state);
     191            }
    192192        }
    193193    }
     
    213213            throw new NullPointerException("pid == null");
    214214        }
     215        if ((this.pid != null) || (state != State.PUBLIC_PENDING)) {
     216            throw new IllegalStateException("illegal state");
     217        }
    215218        this.pid = pid;
     219        this.state = State.PUBLIC;
    216220    }
    217221
     
    220224    }
    221225
    222     @SuppressWarnings("unused")
    223226    @XmlAttribute(name = "persistentId")
    224     private String getXmlPersitentId() {
     227    public String getPersistentIdentifierForXml() {
    225228        if (pid != null) {
    226229            return pid.getIdentifier();
     
    330333            return;
    331334        }
     335        this.setState(state);
    332336        this.setName(vc.getName());
     337        if (vc.getPersistentIdentifier() != null) {
     338            this.setPersistentIdentifier(vc.getPersistentIdentifier());
     339        }
    333340        this.setDescription(vc.getDescription());
    334341        this.setCreationDate(vc.getCreationDate());
Note: See TracChangeset for help on using the changeset viewer.