Changeset 4168


Ignore:
Timestamp:
12/09/13 10:23:33 (10 years ago)
Author:
George.Georgovassilis@mpi.nl
Message:

#471 Group members who didn't directly own components got an error message when viewing them

Location:
ComponentRegistry/branches/ComponentRegistry-1.14.0/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/impl/database
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • ComponentRegistry/branches/ComponentRegistry-1.14.0/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/impl/database/ComponentRegistryDbImpl.java

    r3660 r4168  
    5555 * @author George.Georgovassilis@mpi.nl
    5656 */
    57 public class ComponentRegistryDbImpl extends ComponentRegistryImplBase
    58         implements ComponentRegistry {
    59 
    60     private final static Logger LOG = LoggerFactory
    61             .getLogger(ComponentRegistryDbImpl.class);
    62     private Owner registryOwner;
    63     private ComponentStatus registryStatus;
    64     @Autowired
    65     private Configuration configuration;
    66     @Autowired
    67     @Qualifier("componentsCache")
    68     private CMDComponentSpecCache componentsCache;
    69     @Autowired
    70     @Qualifier("profilesCache")
    71     private CMDComponentSpecCache profilesCache;
    72     // DAO's
    73     @Autowired
    74     private ProfileDescriptionDao profileDescriptionDao;
    75     @Autowired
    76     private ComponentDescriptionDao componentDescriptionDao;
    77     @Autowired
    78     private UserDao userDao;
    79     @Autowired
    80     private CommentsDao commentsDao;
    81     @Autowired
    82     private MDMarshaller marshaller;
    83     @Autowired
    84     private GroupService groupService;
    85 
    86     /**
    87      * Default constructor, to use this as a (spring) bean. The public registry
    88      * by default. Use setStatus() and setOwner() to make it another kind of
    89      * registry.
    90      *
    91      * @see setUser
    92      */
    93     public ComponentRegistryDbImpl() throws TransformerException {
    94         this.registryStatus = ComponentStatus.PUBLISHED;
    95     }
    96 
    97     /**
    98      * Creates a new ComponentRegistry (either public or not) for the provided
    99      * user. Only use for test and/or make sure to inject all dao's and other
    100      * services
    101      *
    102      * @param userId
    103      *            User id of the user to create registry for. Pass null for
    104      *            public
    105      */
    106     public ComponentRegistryDbImpl(ComponentStatus status, Owner owner) {
    107         this.registryStatus = status;
    108         this.registryOwner = owner;
    109     }
    110 
    111     @Override
    112     public List<ProfileDescription> getProfileDescriptions()
    113             throws ComponentRegistryException {
    114         try {
    115             switch (registryStatus) {
    116             // TODO: support other status types
    117             case PRIVATE:
    118                 if (registryOwner == null) {
    119                     throw new ComponentRegistryException(
    120                             "Private workspace without owner!");
    121                 }
    122                 // TODO: Support group space
    123                 return profileDescriptionDao
    124                         .getUserspaceDescriptions(registryOwner.getId());
    125             case PUBLISHED:
    126                 return profileDescriptionDao.getPublicProfileDescriptions();
    127             default:
    128                 throw new ComponentRegistryException("Unsupported status type"
    129                         + registryStatus);
    130             }
    131         } catch (DataAccessException ex) {
    132             throw new ComponentRegistryException(
    133                     "Database access error while trying to get profile descriptions",
    134                     ex);
    135         }
    136     }
    137 
    138     @Override
    139     public ProfileDescription getProfileDescription(String id)
    140             throws ComponentRegistryException {
    141         try {
    142             return profileDescriptionDao.getByCmdId(id, getUserId());
    143         } catch (DataAccessException ex) {
    144             throw new ComponentRegistryException(
    145                     "Database access error while trying to get profile description",
    146                     ex);
    147         }
    148     }
    149 
    150     @Override
    151     public List<ComponentDescription> getComponentDescriptions()
    152             throws ComponentRegistryException {
    153         try {
    154             if (isPublic()) {
    155                 return componentDescriptionDao.getPublicComponentDescriptions();
    156             } else {
    157                 return componentDescriptionDao
    158                         .getUserspaceDescriptions(getUserId());
    159             }
    160         } catch (DataAccessException ex) {
    161             throw new ComponentRegistryException(
    162                     "Database access error while trying to get component descriptions",
    163                     ex);
    164         }
    165     }
    166 
    167     @Override
    168     public ComponentDescription getComponentDescription(String id)
    169             throws ComponentRegistryException {
    170         try {
    171             return componentDescriptionDao.getByCmdId(id, getUserId());
    172         } catch (DataAccessException ex) {
    173             throw new ComponentRegistryException(
    174                     "Database access error while trying to get component description",
    175                     ex);
    176         }
    177     }
    178 
    179     @Override
    180     public List<Comment> getCommentsInProfile(String profileId,
    181             Principal principal) throws ComponentRegistryException {
    182         try {
    183             if (profileDescriptionDao.isInRegistry(profileId, getUserId())) {
    184                 final List<Comment> commentsFromProfile = commentsDao
    185                         .getCommentsFromProfile(profileId);
    186                 setCanDeleteInComments(commentsFromProfile, principal);
    187                 return commentsFromProfile;
    188             } else {
    189                 // Profile does not exist (at least not in this registry)
    190                 throw new ComponentRegistryException("Profile " + profileId
    191                         + " does not exist in specified registry");
    192             }
    193         } catch (DataAccessException ex) {
    194             throw new ComponentRegistryException(
    195                     "Database access error while trying to get list of comments from profile",
    196                     ex);
    197         }
    198     }
    199 
    200     @Override
    201     public Comment getSpecifiedCommentInProfile(String profileId,
    202             String commentId, Principal principal)
    203             throws ComponentRegistryException {
    204         try {
    205             Comment comment = commentsDao
    206                     .getSpecifiedCommentFromProfile(commentId);
    207             if (comment != null
    208                     && profileId.equals(comment.getProfileDescriptionId())
    209                     && profileDescriptionDao.isInRegistry(
    210                             comment.getProfileDescriptionId(), getUserId())) {
    211                 setCanDeleteInComments(Collections.singleton(comment),
    212                         principal);
    213                 return comment;
    214             } else {
    215                 // Comment exists in DB, but profile is not in this registry
    216                 throw new ComponentRegistryException("Comment " + commentId
    217                         + " cannot be found in specified registry");
    218             }
    219         } catch (DataAccessException ex) {
    220             throw new ComponentRegistryException(
    221                     "Database access error while trying to get comment from profile",
    222                     ex);
    223         }
    224     }
    225 
    226     @Override
    227     public List<Comment> getCommentsInComponent(String componentId,
    228             Principal principal) throws ComponentRegistryException {
    229         try {
    230             if (componentDescriptionDao.isInRegistry(componentId, getUserId())) {
    231                 final List<Comment> commentsFromComponent = commentsDao
    232                         .getCommentsFromComponent(componentId);
    233                 setCanDeleteInComments(commentsFromComponent, principal);
    234                 return commentsFromComponent;
    235             } else {
    236                 // Component does not exist (at least not in this registry)
    237                 throw new ComponentRegistryException("Component " + componentId
    238                         + " does not exist in specified registry");
    239             }
    240         } catch (DataAccessException ex) {
    241             throw new ComponentRegistryException(
    242                     "Database access error while trying to get list of comments from component",
    243                     ex);
    244         }
    245     }
    246 
    247     @Override
    248     public Comment getSpecifiedCommentInComponent(String componentId,
    249             String commentId, Principal principal)
    250             throws ComponentRegistryException {
    251         try {
    252             Comment comment = commentsDao
    253                     .getSpecifiedCommentFromComponent(commentId);
    254             if (comment != null
    255                     && componentId.equals(comment.getComponentDescriptionId())
    256                     && componentDescriptionDao.isInRegistry(
    257                             comment.getComponentDescriptionId(), getUserId())) {
    258                 setCanDeleteInComments(Collections.singleton(comment),
    259                         principal);
    260                 return comment;
    261             } else {
    262                 // Comment does not exists in DB or component is not in this
    263                 // registry
    264                 throw new ComponentRegistryException(
    265                         "Comment "
    266                                 + commentId
    267                                 + " cannot be found in specified registry for specified component");
    268             }
    269         } catch (DataAccessException ex) {
    270             throw new ComponentRegistryException(
    271                     "Database access error while trying to get comment from component",
    272                     ex);
    273         }
    274     }
    275 
    276     /**
    277      * Sets the {@link Comment#setCanDelete(boolean) canDelete} property on all
    278      * comments in the provided collection for the perspective of the specified
    279      * principal. Comment owners (determined by {@link Comment#getUserId() }) and
    280      * admins can delete, others cannot.
    281      *
    282      * @param comments
    283      *            comments to configure
    284      * @param principal
    285      *            user to configure for
    286      * @see Comment#isCanDelete()
    287      */
    288     private void setCanDeleteInComments(Collection<Comment> comments,
    289             Principal principal) {
    290         if (principal != null && principal.getName() != null) {
    291             final RegistryUser registryUser = userDao
    292                     .getByPrincipalName(principal.getName());
    293             final String registryUserId = registryUser == null ? null
    294                     : registryUser.getId().toString();
    295             final boolean isAdmin = registryUser != null
    296                     && configuration.isAdminUser(principal);
    297             for (Comment comment : comments) {
    298                 comment.setCanDelete(isAdmin
    299                         || comment.getUserId().equals(registryUserId));
    300             }
    301         }
    302     }
    303 
    304     @Override
    305     public CMDComponentSpec getMDProfile(String id)
    306             throws ComponentRegistryException {
    307         if (inWorkspace(profileDescriptionDao, id)) {
    308             CMDComponentSpec result = profilesCache.get(id);
    309             if (result == null && !profilesCache.containsKey(id)) {
    310                 result = getUncachedMDProfile(id);
    311                 profilesCache.put(id, result);
    312             }
    313             return result;
    314         } else {
    315             // May exist, but not in this workspace
    316             LOG.debug("Could not find profile '{}' in registry '{}'",
    317                     new Object[] { id, this.toString() });
    318             return null;
    319         }
    320     }
    321 
    322     public CMDComponentSpec getUncachedMDProfile(String id)
    323             throws ComponentRegistryException {
    324         try {
    325             return getUncachedMDComponent(id, profileDescriptionDao);
    326         } catch (DataAccessException ex) {
    327             throw new ComponentRegistryException(
    328                     "Database access error while trying to get profile", ex);
    329         }
    330     }
    331 
    332     @Override
    333     public CMDComponentSpec getMDComponent(String id)
    334             throws ComponentRegistryException {
    335         if (inWorkspace(componentDescriptionDao, id)) {
    336             CMDComponentSpec result = componentsCache.get(id);
    337             if (result == null && !componentsCache.containsKey(id)) {
    338                 result = getUncachedMDComponent(id);
    339                 componentsCache.put(id, result);
    340             }
    341             return result;
    342         } else {
    343             // May exist, but not in this workspace
    344             LOG.info("Could not find component '{}' was in registry '{}'",
    345                     new Object[] { id, this.toString() });
    346             return null;
    347         }
    348     }
    349 
    350     public CMDComponentSpec getUncachedMDComponent(String id)
    351             throws ComponentRegistryException {
    352         try {
    353             return getUncachedMDComponent(id, componentDescriptionDao);
    354         } catch (DataAccessException ex) {
    355             throw new ComponentRegistryException(
    356                     "Database access error while trying to get component", ex);
    357         }
    358     }
    359 
    360     @Override
    361     public int register(AbstractDescription description, CMDComponentSpec spec) {
    362         enrichSpecHeader(spec, description);
    363         try {
    364             String xml = componentSpecToString(spec);
    365             // Convert principal name to user record id
    366             Number uid = convertUserInDescription(description);
    367             getDaoForDescription(description).insertDescription(description,
    368                     xml, isPublic(), uid);
    369             invalidateCache(description);
    370             return 0;
    371         } catch (DataAccessException ex) {
    372             LOG.error("Database error while registering component", ex);
    373             return -1;
    374         } catch (JAXBException ex) {
    375             LOG.error("Error while registering component", ex);
    376             return -2;
    377         } catch (UnsupportedEncodingException ex) {
    378             LOG.error("Error while registering component", ex);
    379             return -3;
    380         }
    381     }
    382 
    383     @Override
    384     public int registerComment(Comment comment, String principalName)
    385             throws ComponentRegistryException {
    386         try {
    387             if (comment.getComponentDescriptionId() != null
    388                     && componentDescriptionDao.isInRegistry(
    389                             comment.getComponentDescriptionId(), getUserId())
    390                     || comment.getProfileDescriptionId() != null
    391                     && profileDescriptionDao.isInRegistry(
    392                             comment.getProfileDescriptionId(), getUserId())) {
    393                 // Convert principal name to user record id
    394                 Number uid = convertUserIdInComment(comment, principalName);
    395                 // Set date to current date
    396                 comment.setCommentDate(Comment.createNewDate());
    397                 Number commentId = commentsDao.insertComment(comment, uid);
    398                 comment.setId(commentId.toString());
    399             } else {
    400                 throw new ComponentRegistryException(
    401                         "Cannot insert comment into this registry. Unknown profileId or componentId");
    402             }
    403             return 0;
    404         } catch (DataAccessException ex) {
    405             LOG.error("Database error while registering component", ex);
    406             return -1;
    407         }
    408     }
    409 
    410     /**
    411      * Calling service sets user id to principle. Our task is to convert this to
    412      * an id for later reference. If none is set and this is a user's workspace,
    413      * set from that user's id.
    414      *
    415      * It also sets the name in the description according to the display name in
    416      * the database.
    417      *
    418      * @param description
    419      *            Description containing principle name as userId
    420      * @return Id (from database)
    421      * @throws DataAccessException
    422      */
    423     private Number convertUserInDescription(AbstractDescription description)
    424             throws DataAccessException {
    425         Number uid = null;
    426         String name = null;
    427         if (description.getUserId() != null) {
    428             RegistryUser user = userDao.getByPrincipalName(description
    429                     .getUserId());
    430             if (user != null) {
    431                 uid = user.getId();
    432                 name = user.getName();
    433             }
    434         } else {
    435             uid = getUserId(); // this can be null as well
    436         }
    437         if (uid != null) {
    438             description.setUserId(uid.toString());
    439         }
    440         if (name != null) {
    441             description.setCreatorName(name);
    442         }
    443         return uid;
    444     }
    445 
    446     /**
    447      * Calling service sets user id to principle. Our task is to convert this to
    448      * an id for later reference. If none is set and this is a user's workspace,
    449      * set from that user's id.
    450      *
    451      * @param comment
    452      *            Comment containing principle name as userId
    453      * @return Id (from database)
    454      * @throws DataAccessException
    455      */
    456     private Number convertUserIdInComment(Comment comment, String principalName)
    457             throws DataAccessException, ComponentRegistryException {
    458         if (principalName != null) {
    459             RegistryUser user = userDao.getByPrincipalName(principalName);
    460             if (user != null) {
    461                 Number id = user.getId();
    462                 if (id != null) {
    463                     // Set user id in comment for convenience of calling method
    464                     comment.setUserId(id.toString());
    465                     // Set name to user's preferred display name
    466                     comment.setUserName(user.getName());
    467                     return id;
     57public class ComponentRegistryDbImpl extends ComponentRegistryImplBase implements ComponentRegistry {
     58
     59        private final static Logger LOG = LoggerFactory.getLogger(ComponentRegistryDbImpl.class);
     60        private Owner registryOwner;
     61        private ComponentStatus registryStatus;
     62        @Autowired
     63        private Configuration configuration;
     64        @Autowired
     65        @Qualifier("componentsCache")
     66        private CMDComponentSpecCache componentsCache;
     67        @Autowired
     68        @Qualifier("profilesCache")
     69        private CMDComponentSpecCache profilesCache;
     70        // DAO's
     71        @Autowired
     72        private ProfileDescriptionDao profileDescriptionDao;
     73        @Autowired
     74        private ComponentDescriptionDao componentDescriptionDao;
     75        @Autowired
     76        private UserDao userDao;
     77        @Autowired
     78        private CommentsDao commentsDao;
     79        @Autowired
     80        private MDMarshaller marshaller;
     81        @Autowired
     82        private GroupService groupService;
     83
     84        /**
     85         * Default constructor, to use this as a (spring) bean. The public registry
     86         * by default. Use setStatus() and setOwner() to make it another kind of
     87         * registry.
     88         *
     89         * @see setUser
     90         */
     91        public ComponentRegistryDbImpl() throws TransformerException {
     92                this.registryStatus = ComponentStatus.PUBLISHED;
     93        }
     94
     95        /**
     96         * Creates a new ComponentRegistry (either public or not) for the provided
     97         * user. Only use for test and/or make sure to inject all dao's and other
     98         * services
     99         *
     100         * @param userId
     101         *            User id of the user to create registry for. Pass null for
     102         *            public
     103         */
     104        public ComponentRegistryDbImpl(ComponentStatus status, Owner owner) {
     105                this.registryStatus = status;
     106                this.registryOwner = owner;
     107        }
     108
     109        @Override
     110        public List<ProfileDescription> getProfileDescriptions() throws ComponentRegistryException {
     111                try {
     112                        switch (registryStatus) {
     113                        // TODO: support other status types
     114                        case PRIVATE:
     115                                if (registryOwner == null) {
     116                                        throw new ComponentRegistryException("Private workspace without owner!");
     117                                }
     118                                // TODO: Support group space
     119                                return profileDescriptionDao.getUserspaceDescriptions(registryOwner.getId());
     120                        case PUBLISHED:
     121                                return profileDescriptionDao.getPublicProfileDescriptions();
     122                        default:
     123                                throw new ComponentRegistryException("Unsupported status type" + registryStatus);
     124                        }
     125                } catch (DataAccessException ex) {
     126                        throw new ComponentRegistryException("Database access error while trying to get profile descriptions", ex);
     127                }
     128        }
     129
     130        @Override
     131        public ProfileDescription getProfileDescription(String id) throws ComponentRegistryException {
     132                try {
     133                        return profileDescriptionDao.getByCmdId(id, getUserId());
     134                } catch (DataAccessException ex) {
     135                        throw new ComponentRegistryException("Database access error while trying to get profile description", ex);
     136                }
     137        }
     138
     139        @Override
     140        public List<ComponentDescription> getComponentDescriptions() throws ComponentRegistryException {
     141                try {
     142                        if (isPublic()) {
     143                                return componentDescriptionDao.getPublicComponentDescriptions();
     144                        } else {
     145                                return componentDescriptionDao.getUserspaceDescriptions(getUserId());
     146                        }
     147                } catch (DataAccessException ex) {
     148                        throw new ComponentRegistryException("Database access error while trying to get component descriptions", ex);
     149                }
     150        }
     151
     152        @Override
     153        public ComponentDescription getComponentDescription(String id) throws ComponentRegistryException {
     154                try {
     155                        return componentDescriptionDao.getByCmdId(id, getUserId());
     156                } catch (DataAccessException ex) {
     157                        throw new ComponentRegistryException("Database access error while trying to get component description", ex);
     158                }
     159        }
     160
     161        @Override
     162        public List<Comment> getCommentsInProfile(String profileId, Principal principal) throws ComponentRegistryException {
     163                try {
     164                        if (profileDescriptionDao.isInRegistry(profileId, getUserId())) {
     165                                final List<Comment> commentsFromProfile = commentsDao.getCommentsFromProfile(profileId);
     166                                setCanDeleteInComments(commentsFromProfile, principal);
     167                                return commentsFromProfile;
     168                        } else {
     169                                // Profile does not exist (at least not in this registry)
     170                                throw new ComponentRegistryException("Profile " + profileId + " does not exist in specified registry");
     171                        }
     172                } catch (DataAccessException ex) {
     173                        throw new ComponentRegistryException(
     174                                        "Database access error while trying to get list of comments from profile", ex);
     175                }
     176        }
     177
     178        @Override
     179        public Comment getSpecifiedCommentInProfile(String profileId, String commentId, Principal principal)
     180                        throws ComponentRegistryException {
     181                try {
     182                        Comment comment = commentsDao.getSpecifiedCommentFromProfile(commentId);
     183                        if (comment != null && profileId.equals(comment.getProfileDescriptionId())
     184                                        && profileDescriptionDao.isInRegistry(comment.getProfileDescriptionId(), getUserId())) {
     185                                setCanDeleteInComments(Collections.singleton(comment), principal);
     186                                return comment;
     187                        } else {
     188                                // Comment exists in DB, but profile is not in this registry
     189                                throw new ComponentRegistryException("Comment " + commentId + " cannot be found in specified registry");
     190                        }
     191                } catch (DataAccessException ex) {
     192                        throw new ComponentRegistryException("Database access error while trying to get comment from profile", ex);
     193                }
     194        }
     195
     196        @Override
     197        public List<Comment> getCommentsInComponent(String componentId, Principal principal)
     198                        throws ComponentRegistryException {
     199                try {
     200                        if (componentDescriptionDao.isInRegistry(componentId, getUserId())) {
     201                                final List<Comment> commentsFromComponent = commentsDao.getCommentsFromComponent(componentId);
     202                                setCanDeleteInComments(commentsFromComponent, principal);
     203                                return commentsFromComponent;
     204                        } else {
     205                                // Component does not exist (at least not in this registry)
     206                                throw new ComponentRegistryException("Component " + componentId
     207                                                + " does not exist in specified registry");
     208                        }
     209                } catch (DataAccessException ex) {
     210                        throw new ComponentRegistryException(
     211                                        "Database access error while trying to get list of comments from component", ex);
     212                }
     213        }
     214
     215        @Override
     216        public Comment getSpecifiedCommentInComponent(String componentId, String commentId, Principal principal)
     217                        throws ComponentRegistryException {
     218                try {
     219                        Comment comment = commentsDao.getSpecifiedCommentFromComponent(commentId);
     220                        if (comment != null && componentId.equals(comment.getComponentDescriptionId())
     221                                        && componentDescriptionDao.isInRegistry(comment.getComponentDescriptionId(), getUserId())) {
     222                                setCanDeleteInComments(Collections.singleton(comment), principal);
     223                                return comment;
     224                        } else {
     225                                // Comment does not exists in DB or component is not in this
     226                                // registry
     227                                throw new ComponentRegistryException("Comment " + commentId
     228                                                + " cannot be found in specified registry for specified component");
     229                        }
     230                } catch (DataAccessException ex) {
     231                        throw new ComponentRegistryException("Database access error while trying to get comment from component", ex);
     232                }
     233        }
     234
     235        /**
     236         * Sets the {@link Comment#setCanDelete(boolean) canDelete} property on all
     237         * comments in the provided collection for the perspective of the specified
     238         * principal. Comment owners (determined by {@link Comment#getUserId() }) and
     239         * admins can delete, others cannot.
     240         *
     241         * @param comments
     242         *            comments to configure
     243         * @param principal
     244         *            user to configure for
     245         * @see Comment#isCanDelete()
     246         */
     247        private void setCanDeleteInComments(Collection<Comment> comments, Principal principal) {
     248                if (principal != null && principal.getName() != null) {
     249                        final RegistryUser registryUser = userDao.getByPrincipalName(principal.getName());
     250                        final String registryUserId = registryUser == null ? null : registryUser.getId().toString();
     251                        final boolean isAdmin = registryUser != null && configuration.isAdminUser(principal);
     252                        for (Comment comment : comments) {
     253                                comment.setCanDelete(isAdmin || comment.getUserId().equals(registryUserId));
     254                        }
     255                }
     256        }
     257
     258        @Override
     259        public CMDComponentSpec getMDProfile(String id) throws ComponentRegistryException {
     260                if (inWorkspace(profileDescriptionDao, id)||canCurrentUserAccessDescription(profileDescriptionDao, id)) {
     261                        CMDComponentSpec result = profilesCache.get(id);
     262                        if (result == null && !profilesCache.containsKey(id)) {
     263                                result = getUncachedMDProfile(id);
     264                                profilesCache.put(id, result);
     265                        }
     266                        return result;
    468267                } else {
    469                     throw new ComponentRegistryException(
    470                             "Cannot find user with principal name: "
    471                                     + principalName);
    472                 }
    473             }
    474         }
    475         return null;
    476     }
    477 
    478     @Override
    479     public int update(AbstractDescription description, CMDComponentSpec spec,
    480             Principal principal, boolean forceUpdate) {
    481         try {
    482             checkAuthorisation(description, principal);
    483             checkAge(description, principal);
    484             // For public components, check if used in other components or
    485             // profiles (unless forced)
    486             if (!forceUpdate && this.isPublic() && !description.isProfile()) {
    487                 checkStillUsed(description.getId());
    488             }
    489             AbstractDescriptionDao<?> dao = getDaoForDescription(description);
    490             dao.updateDescription(getIdForDescription(description),
    491                     description, componentSpecToString(spec));
    492             invalidateCache(description);
    493             return 0;
    494         } catch (JAXBException ex) {
    495             LOG.error("Error while updating component", ex);
    496             return -1;
    497         } catch (UnsupportedEncodingException ex) {
    498             LOG.error("Error while updating component", ex);
    499             return -1;
    500         } catch (IllegalArgumentException ex) {
    501             LOG.error("Error while updating component", ex);
    502             return -1;
    503         } catch (UserUnauthorizedException e) {
    504             LOG.error("Error while updating component", e);
    505             return -1;
    506         } catch (DeleteFailedException e) {
    507             LOG.error("Error while updating component", e);
    508             return -1;
    509         } catch (ComponentRegistryException e) {
    510             LOG.error("Error while updating component", e);
    511             return -1;
    512         }
    513     }
    514 
    515     @Override
    516     public int publish(AbstractDescription desc, CMDComponentSpec spec,
    517             Principal principal) {
    518         int result = 0;
    519         AbstractDescriptionDao<?> dao = getDaoForDescription(desc);
    520         if (!isPublic()) { // if already in public workspace there is nothing
    521                            // todo
    522             desc.setHref(AbstractDescription.createPublicHref(desc.getHref()));
    523             Number id = getIdForDescription(desc);
    524             try {
    525                 // Update description & content
    526                 dao.updateDescription(id, desc, componentSpecToString(spec));
    527                 // Set to public
    528                 dao.setPublished(id, true);
    529             } catch (DataAccessException ex) {
    530                 LOG.error("Database error while updating component", ex);
    531                 return -1;
    532             } catch (JAXBException ex) {
    533                 LOG.error("Error while updating component", ex);
    534                 return -2;
    535             } catch (UnsupportedEncodingException ex) {
    536                 LOG.error("Error while updating component", ex);
    537                 return -3;
    538             }
    539         }
    540         return result;
    541     }
    542 
    543     @Override
    544     public void getMDProfileAsXml(String profileId, OutputStream output)
    545             throws ComponentRegistryException {
    546         CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl
    547                 .expandProfile(profileId, this);
    548         writeXml(expandedSpec, output);
    549     }
    550 
    551     @Override
    552     public void getMDProfileAsXsd(String profileId, OutputStream outputStream)
    553             throws ComponentRegistryException {
    554         CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl
    555                 .expandProfile(profileId, this);
    556         writeXsd(expandedSpec, outputStream);
    557     }
    558 
    559     @Override
    560     public void getMDComponentAsXml(String componentId, OutputStream output)
    561             throws ComponentRegistryException {
    562         CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl
    563                 .expandComponent(componentId, this);
    564         writeXml(expandedSpec, output);
    565     }
    566 
    567     @Override
    568     public void getMDComponentAsXsd(String componentId,
    569             OutputStream outputStream) throws ComponentRegistryException {
    570         CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl
    571                 .expandComponent(componentId, this);
    572         writeXsd(expandedSpec, outputStream);
    573     }
    574 
    575     @Override
    576     public void deleteMDProfile(String profileId, Principal principal)
    577             throws UserUnauthorizedException, DeleteFailedException,
    578             ComponentRegistryException {
    579         ProfileDescription desc = getProfileDescription(profileId);
    580         if (desc != null) {
    581             try {
    582                 checkAuthorisation(desc, principal);
    583                 checkAge(desc, principal);
    584                 profileDescriptionDao.setDeleted(desc, true);
    585                 invalidateCache(desc);
    586             } catch (DataAccessException ex) {
    587                 throw new DeleteFailedException(
    588                         "Database access error while trying to delete profile",
    589                         ex);
    590             }
    591         }
    592     }
    593 
    594     @Override
    595     public void deleteMDComponent(String componentId, Principal principal,
    596             boolean forceDelete) throws UserUnauthorizedException,
    597             DeleteFailedException, ComponentRegistryException {
    598         ComponentDescription desc = componentDescriptionDao
    599                 .getByCmdId(componentId);
    600         if (desc != null) {
    601             try {
    602                 checkAuthorisation(desc, principal);
    603                 checkAge(desc, principal);
    604 
    605                 if (!forceDelete) {
    606                     checkStillUsed(componentId);
    607                 }
    608                 componentDescriptionDao.setDeleted(desc, true);
    609                 invalidateCache(desc);
    610             } catch (DataAccessException ex) {
    611                 throw new DeleteFailedException(
    612                         "Database access error while trying to delete component",
    613                         ex);
    614             }
    615         }
    616     }
    617 
    618     /**
    619      *
    620      * @return whether this is the public registry
    621      * @deprecated use {@link #getStatus() } to check if this is the
    622      *             {@link ComponentStatus#PUBLISHED public registry}
    623      */
    624     @Override
    625     @Deprecated
    626     public boolean isPublic() {
    627         return registryStatus == ComponentStatus.PUBLISHED;
    628     }
    629 
    630     /**
    631      * @return The user id, or null if there is no owner or it is not a user.
    632      */
    633     private Number getUserId() {
    634         if (registryOwner instanceof OwnerUser) {
    635             return registryOwner.getId();
    636         } else {
    637             return null;
    638         }
    639     }
    640 
    641     @Override
    642     public Owner getOwner() {
    643         return registryOwner;
    644     }
    645 
    646     /**
    647      * Sets status and owner of this registry
    648      *
    649      * @param status
    650      *            new status for registry
    651      * @param owner
    652      *            new owner for registry
    653      */
    654     public void setStatus(ComponentStatus status, Owner owner) {
    655         setStatus(status);
    656         this.registryOwner = owner;
    657     }
    658 
    659     public void setStatus(ComponentStatus status) {
    660         this.registryStatus = status;
    661     }
    662 
    663     @Override
    664     public ComponentStatus getStatus() {
    665         return registryStatus;
    666     }
    667 
    668     private void invalidateCache(AbstractDescription description) {
    669         if (description.isProfile()) {
    670             profilesCache.remove(description.getId());
    671         } else {
    672             componentsCache.remove(description.getId());
    673         }
    674     }
    675 
    676     private AbstractDescriptionDao<?> getDaoForDescription(
    677             AbstractDescription description) {
    678         return description.isProfile() ? profileDescriptionDao
    679                 : componentDescriptionDao;
    680     }
    681 
    682     /**
    683      * Looks up description on basis of CMD Id. This will also check if such a
    684      * record even exists.
    685      *
    686      * @param description
    687      *            Description to look up
    688      * @return Database id for description
    689      * @throws IllegalArgumentException
    690      *             If description with non-existing id is passed
    691      */
    692     private Number getIdForDescription(AbstractDescription description)
    693             throws IllegalArgumentException {
    694         Number dbId = null;
    695         AbstractDescriptionDao<?> dao = getDaoForDescription(description);
    696         try {
    697             dbId = dao.getDbId(description.getId());
    698         } catch (DataAccessException ex) {
    699             LOG.error(
    700                     "Error getting dbId for component with id "
    701                             + description.getId(), ex);
    702         }
    703         if (dbId == null) {
    704             throw new IllegalArgumentException(
    705                     "Could not get database Id for description");
    706         } else {
    707             return dbId;
    708         }
    709     }
    710 
    711     private String componentSpecToString(CMDComponentSpec spec)
    712             throws UnsupportedEncodingException, JAXBException {
    713         ByteArrayOutputStream os = new ByteArrayOutputStream();
    714         getMarshaller().marshal(spec, os);
    715         String xml = os.toString("UTF-8");
    716         return xml;
    717     }
    718 
    719     private CMDComponentSpec getUncachedMDComponent(String id,
    720             AbstractDescriptionDao dao) {
    721         String xml = dao.getContent(false, id);
    722         if (xml != null) {
    723             try {
    724                 InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
    725                 return getMarshaller().unmarshal(CMDComponentSpec.class, is,
    726                         null);
    727 
    728             } catch (JAXBException ex) {
    729                 LOG.error("Error while unmarshalling", ex);
    730             } catch (UnsupportedEncodingException ex) {
    731                 LOG.error("Exception while reading XML from database", ex);
    732             }
    733         }
    734         return null;
    735     }
    736 
    737     private void checkAuthorisation(AbstractDescription desc,
    738             Principal principal) throws UserUnauthorizedException {
    739         if (!isOwnerOfDescription(desc, principal.getName())
    740                 && !configuration.isAdminUser(principal)) {
    741             throw new UserUnauthorizedException("Unauthorized operation user '"
    742                     + principal.getName()
    743                     + "' is not the creator (nor an administrator) of the "
    744                     + (desc.isProfile() ? "profile" : "component") + "(" + desc
    745                     + ").");
    746         }
    747     }
    748 
    749     private void checkAuthorisationComment(Comment desc, Principal principal)
    750             throws UserUnauthorizedException {
    751         if (!isOwnerOfComment(desc, principal.getName())
    752                 && !configuration.isAdminUser(principal)) {
    753             throw new UserUnauthorizedException("Unauthorized operation user '"
    754                     + principal.getName()
    755                     + "' is not the creator (nor an administrator) of the "
    756                     + (desc.getId()) + "(" + desc + ").");
    757         }
    758     }
    759 
    760     private boolean isOwnerOfDescription(AbstractDescription desc,
    761             String principalName) {
    762         String owner = getDaoForDescription(desc).getOwnerPrincipalName(
    763                 getIdForDescription(desc));
    764         return owner != null // If owner is null, no one can be owner
    765                 && principalName.equals(owner);
    766     }
    767 
    768     private boolean isOwnerOfComment(Comment com, String principalName) {
    769         String owner = commentsDao.getOwnerPrincipalName(Integer.parseInt(com
    770                 .getId()));
    771         return owner != null // If owner is null, no one can be owner
    772                 && principalName.equals(owner);
    773     }
    774 
    775     private void checkAge(AbstractDescription desc, Principal principal)
    776             throws DeleteFailedException {
    777         if (isPublic() && !configuration.isAdminUser(principal)) {
    778             try {
    779                 Date regDate = AbstractDescription.getDate(desc
    780                         .getRegistrationDate());
    781                 Calendar calendar = Calendar.getInstance();
    782                 calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
    783                 if (regDate.before(calendar.getTime())) { // More then month old
    784                     throw new DeleteFailedException(
    785                             "The "
    786                                     + (desc.isProfile() ? "Profile"
    787                                             : "Component")
    788                                     + " is more then a month old and cannot be deleted anymore. It might have been used to create metadata, deleting it would invalidate that metadata.");
    789                 }
    790             } catch (ParseException e) {
    791                 LOG.error("Cannot parse date of " + desc + " Error:" + e);
    792             }
    793         }
    794     }
    795 
    796     private boolean inWorkspace(AbstractDescriptionDao<?> dao, String cmdId) {
    797         if (isPublic()) {
    798             return dao.isPublic(cmdId);
    799         } else {
    800             return dao.isInUserSpace(cmdId, getUserId());
    801         }
    802     }
    803 
    804     @Override
    805     public String getName() {
    806         if (isPublic()) {
    807             return ComponentRegistry.PUBLIC_NAME;
    808         } else {
    809             return "Registry of " + userDao.getById(getUserId()).getName();
    810         }
    811     }
    812 
    813     @Override
    814     public List<ProfileDescription> getDeletedProfileDescriptions() {
    815         return profileDescriptionDao.getDeletedDescriptions(getUserId());
    816     }
    817 
    818     @Override
    819     public List<ComponentDescription> getDeletedComponentDescriptions() {
    820         return componentDescriptionDao.getDeletedDescriptions(getUserId());
    821     }
    822 
    823     @Override
    824     public void deleteComment(String commentId, Principal principal)
    825             throws IOException, ComponentRegistryException,
    826             UserUnauthorizedException, DeleteFailedException {
    827         try {
    828             Comment comment = commentsDao.getById(Integer.parseInt(commentId));
    829             if (comment != null
    830                     // Comment must have an existing (in this registry)
    831                     // componentId or profileId
    832                     && (comment.getComponentDescriptionId() != null
    833                             && componentDescriptionDao.isInRegistry(
    834                                     comment.getComponentDescriptionId(),
    835                                     getUserId()) || comment
    836                             .getProfileDescriptionId() != null
    837                             && profileDescriptionDao.isInRegistry(
    838                                     comment.getProfileDescriptionId(),
    839                                     getUserId()))) {
    840                 checkAuthorisationComment(comment, principal);
    841                 commentsDao.deleteComment(comment);
    842             } else {
    843                 // Comment exists in DB, but component is not in this registry
    844                 throw new ComponentRegistryException("Comment " + commentId
    845                         + " cannot be found in specified registry");
    846             }
    847         } catch (DataAccessException ex) {
    848             throw new DeleteFailedException(
    849                     "Database access error while trying to delete component",
    850                     ex);
    851         } catch (NumberFormatException ex) {
    852             throw new DeleteFailedException(
    853                     "Illegal comment ID, cannot parse integer", ex);
    854         }
    855     }
    856 
    857     @Override
    858     public CMDComponentSpecExpander getExpander() {
    859         return new CMDComponentSpecExpanderDbImpl(this);
    860     }
    861 
    862     @Override
    863     protected MDMarshaller getMarshaller() {
    864         return marshaller;
    865     }
    866 
    867     @Override
    868     public String toString() {
    869         return getName();
    870     }
    871 
    872     @Override
    873     public List<ComponentDescription> getComponentDescriptionsInGroup(
    874             String principalName, String groupId) throws ComponentRegistryException {
    875         List<String> componentIds = groupService.getComponentIdsInGroup(Long.parseLong(groupId));
    876         List<ComponentDescription> components = new ArrayList<ComponentDescription>();
    877         for (String id:componentIds) {
    878             ComponentDescription componentDescription = getComponentDescription(id);
    879             //minor robustness consideration: if, for whatever reason, the component for an ownership has been removed, don't return a null but just skip it
    880             if (componentDescription!=null)
    881                 components.add(componentDescription);
    882         }
    883         return components;
    884     }
    885 
    886     @Override
    887     public List<ProfileDescription> getProfileDescriptionsForMetadaEditor(
    888             String groupId) throws ComponentRegistryException {
    889         List<String> componentIds = groupService.getProfileIdsInGroup(Long.parseLong(groupId));
    890         List<ProfileDescription> profiles = new ArrayList<ProfileDescription>();
    891         for (String id:componentIds) {
    892             ProfileDescription profile = getProfileDescription(id);
    893             if (profile!=null)
    894                 profiles.add(profile);
    895         }
    896         return profiles;
    897     }
    898 
    899     @Override
    900     public List<ProfileDescription> getProfileDescriptionsInGroup(String groupId)
    901             throws ComponentRegistryException {
    902         List<String> componentIds = groupService.getProfileIdsInGroup(Long.parseLong(groupId));
    903         List<ProfileDescription> profiles = new ArrayList<ProfileDescription>();
    904         for (String id:componentIds)
    905             profiles.add(getProfileDescription(id));
    906         return profiles;
    907     }
     268                        // May exist, but not in this workspace
     269                        LOG.debug("Could not find profile '{}' in registry '{}'", new Object[] { id, this.toString() });
     270                        return null;
     271                }
     272        }
     273
     274        public CMDComponentSpec getUncachedMDProfile(String id) throws ComponentRegistryException {
     275                try {
     276                        return getUncachedMDComponent(id, profileDescriptionDao);
     277                } catch (DataAccessException ex) {
     278                        throw new ComponentRegistryException("Database access error while trying to get profile", ex);
     279                }
     280        }
     281
     282        @Override
     283        public CMDComponentSpec getMDComponent(String id) throws ComponentRegistryException {
     284                if (inWorkspace(componentDescriptionDao, id)||canCurrentUserAccessDescription(componentDescriptionDao, id)) {
     285                        CMDComponentSpec result = componentsCache.get(id);
     286                        if (result == null && !componentsCache.containsKey(id)) {
     287                                result = getUncachedMDComponent(id);
     288                                componentsCache.put(id, result);
     289                        }
     290                        return result;
     291                } else {
     292                        // May exist, but not in this workspace
     293                        LOG.info("Could not find component '{}' was in registry '{}'", new Object[] { id, this.toString() });
     294                        return null;
     295                }
     296        }
     297
     298        public CMDComponentSpec getUncachedMDComponent(String id) throws ComponentRegistryException {
     299                try {
     300                        return getUncachedMDComponent(id, componentDescriptionDao);
     301                } catch (DataAccessException ex) {
     302                        throw new ComponentRegistryException("Database access error while trying to get component", ex);
     303                }
     304        }
     305
     306        @Override
     307        public int register(AbstractDescription description, CMDComponentSpec spec) {
     308                enrichSpecHeader(spec, description);
     309                try {
     310                        String xml = componentSpecToString(spec);
     311                        // Convert principal name to user record id
     312                        Number uid = convertUserInDescription(description);
     313                        getDaoForDescription(description).insertDescription(description, xml, isPublic(), uid);
     314                        invalidateCache(description);
     315                        return 0;
     316                } catch (DataAccessException ex) {
     317                        LOG.error("Database error while registering component", ex);
     318                        return -1;
     319                } catch (JAXBException ex) {
     320                        LOG.error("Error while registering component", ex);
     321                        return -2;
     322                } catch (UnsupportedEncodingException ex) {
     323                        LOG.error("Error while registering component", ex);
     324                        return -3;
     325                }
     326        }
     327
     328        @Override
     329        public int registerComment(Comment comment, String principalName) throws ComponentRegistryException {
     330                try {
     331                        if (comment.getComponentDescriptionId() != null
     332                                        && componentDescriptionDao.isInRegistry(comment.getComponentDescriptionId(), getUserId())
     333                                        || comment.getProfileDescriptionId() != null
     334                                        && profileDescriptionDao.isInRegistry(comment.getProfileDescriptionId(), getUserId())) {
     335                                // Convert principal name to user record id
     336                                Number uid = convertUserIdInComment(comment, principalName);
     337                                // Set date to current date
     338                                comment.setCommentDate(Comment.createNewDate());
     339                                Number commentId = commentsDao.insertComment(comment, uid);
     340                                comment.setId(commentId.toString());
     341                        } else {
     342                                throw new ComponentRegistryException(
     343                                                "Cannot insert comment into this registry. Unknown profileId or componentId");
     344                        }
     345                        return 0;
     346                } catch (DataAccessException ex) {
     347                        LOG.error("Database error while registering component", ex);
     348                        return -1;
     349                }
     350        }
     351
     352        /**
     353         * Calling service sets user id to principle. Our task is to convert this to
     354         * an id for later reference. If none is set and this is a user's workspace,
     355         * set from that user's id.
     356         *
     357         * It also sets the name in the description according to the display name in
     358         * the database.
     359         *
     360         * @param description
     361         *            Description containing principle name as userId
     362         * @return Id (from database)
     363         * @throws DataAccessException
     364         */
     365        private Number convertUserInDescription(AbstractDescription description) throws DataAccessException {
     366                Number uid = null;
     367                String name = null;
     368                if (description.getUserId() != null) {
     369                        RegistryUser user = userDao.getByPrincipalName(description.getUserId());
     370                        if (user != null) {
     371                                uid = user.getId();
     372                                name = user.getName();
     373                        }
     374                } else {
     375                        uid = getUserId(); // this can be null as well
     376                }
     377                if (uid != null) {
     378                        description.setUserId(uid.toString());
     379                }
     380                if (name != null) {
     381                        description.setCreatorName(name);
     382                }
     383                return uid;
     384        }
     385
     386        /**
     387         * Calling service sets user id to principle. Our task is to convert this to
     388         * an id for later reference. If none is set and this is a user's workspace,
     389         * set from that user's id.
     390         *
     391         * @param comment
     392         *            Comment containing principle name as userId
     393         * @return Id (from database)
     394         * @throws DataAccessException
     395         */
     396        private Number convertUserIdInComment(Comment comment, String principalName) throws DataAccessException,
     397                        ComponentRegistryException {
     398                if (principalName != null) {
     399                        RegistryUser user = userDao.getByPrincipalName(principalName);
     400                        if (user != null) {
     401                                Number id = user.getId();
     402                                if (id != null) {
     403                                        // Set user id in comment for convenience of calling method
     404                                        comment.setUserId(id.toString());
     405                                        // Set name to user's preferred display name
     406                                        comment.setUserName(user.getName());
     407                                        return id;
     408                                } else {
     409                                        throw new ComponentRegistryException("Cannot find user with principal name: " + principalName);
     410                                }
     411                        }
     412                }
     413                return null;
     414        }
     415
     416        @Override
     417        public int update(AbstractDescription description, CMDComponentSpec spec, Principal principal, boolean forceUpdate) {
     418                try {
     419                        checkAuthorisation(description, principal);
     420                        checkAge(description, principal);
     421                        // For public components, check if used in other components or
     422                        // profiles (unless forced)
     423                        if (!forceUpdate && this.isPublic() && !description.isProfile()) {
     424                                checkStillUsed(description.getId());
     425                        }
     426                        AbstractDescriptionDao<?> dao = getDaoForDescription(description);
     427                        dao.updateDescription(getIdForDescription(description), description, componentSpecToString(spec));
     428                        invalidateCache(description);
     429                        return 0;
     430                } catch (JAXBException ex) {
     431                        LOG.error("Error while updating component", ex);
     432                        return -1;
     433                } catch (UnsupportedEncodingException ex) {
     434                        LOG.error("Error while updating component", ex);
     435                        return -1;
     436                } catch (IllegalArgumentException ex) {
     437                        LOG.error("Error while updating component", ex);
     438                        return -1;
     439                } catch (UserUnauthorizedException e) {
     440                        LOG.error("Error while updating component", e);
     441                        return -1;
     442                } catch (DeleteFailedException e) {
     443                        LOG.error("Error while updating component", e);
     444                        return -1;
     445                } catch (ComponentRegistryException e) {
     446                        LOG.error("Error while updating component", e);
     447                        return -1;
     448                }
     449        }
     450
     451        @Override
     452        public int publish(AbstractDescription desc, CMDComponentSpec spec, Principal principal) {
     453                int result = 0;
     454                AbstractDescriptionDao<?> dao = getDaoForDescription(desc);
     455                if (!isPublic()) { // if already in public workspace there is nothing
     456                        // todo
     457                        desc.setHref(AbstractDescription.createPublicHref(desc.getHref()));
     458                        Number id = getIdForDescription(desc);
     459                        try {
     460                                // Update description & content
     461                                dao.updateDescription(id, desc, componentSpecToString(spec));
     462                                // Set to public
     463                                dao.setPublished(id, true);
     464                        } catch (DataAccessException ex) {
     465                                LOG.error("Database error while updating component", ex);
     466                                return -1;
     467                        } catch (JAXBException ex) {
     468                                LOG.error("Error while updating component", ex);
     469                                return -2;
     470                        } catch (UnsupportedEncodingException ex) {
     471                                LOG.error("Error while updating component", ex);
     472                                return -3;
     473                        }
     474                }
     475                return result;
     476        }
     477
     478        @Override
     479        public void getMDProfileAsXml(String profileId, OutputStream output) throws ComponentRegistryException {
     480                CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl.expandProfile(profileId, this);
     481                writeXml(expandedSpec, output);
     482        }
     483
     484        @Override
     485        public void getMDProfileAsXsd(String profileId, OutputStream outputStream) throws ComponentRegistryException {
     486                CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl.expandProfile(profileId, this);
     487                writeXsd(expandedSpec, outputStream);
     488        }
     489
     490        @Override
     491        public void getMDComponentAsXml(String componentId, OutputStream output) throws ComponentRegistryException {
     492                CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl.expandComponent(componentId, this);
     493                writeXml(expandedSpec, output);
     494        }
     495
     496        @Override
     497        public void getMDComponentAsXsd(String componentId, OutputStream outputStream) throws ComponentRegistryException {
     498                CMDComponentSpec expandedSpec = CMDComponentSpecExpanderDbImpl.expandComponent(componentId, this);
     499                writeXsd(expandedSpec, outputStream);
     500        }
     501
     502        @Override
     503        public void deleteMDProfile(String profileId, Principal principal) throws UserUnauthorizedException,
     504                        DeleteFailedException, ComponentRegistryException {
     505                ProfileDescription desc = getProfileDescription(profileId);
     506                if (desc != null) {
     507                        try {
     508                                checkAuthorisation(desc, principal);
     509                                checkAge(desc, principal);
     510                                profileDescriptionDao.setDeleted(desc, true);
     511                                invalidateCache(desc);
     512                        } catch (DataAccessException ex) {
     513                                throw new DeleteFailedException("Database access error while trying to delete profile", ex);
     514                        }
     515                }
     516        }
     517
     518        @Override
     519        public void deleteMDComponent(String componentId, Principal principal, boolean forceDelete)
     520                        throws UserUnauthorizedException, DeleteFailedException, ComponentRegistryException {
     521                ComponentDescription desc = componentDescriptionDao.getByCmdId(componentId);
     522                if (desc != null) {
     523                        try {
     524                                checkAuthorisation(desc, principal);
     525                                checkAge(desc, principal);
     526
     527                                if (!forceDelete) {
     528                                        checkStillUsed(componentId);
     529                                }
     530                                componentDescriptionDao.setDeleted(desc, true);
     531                                invalidateCache(desc);
     532                        } catch (DataAccessException ex) {
     533                                throw new DeleteFailedException("Database access error while trying to delete component", ex);
     534                        }
     535                }
     536        }
     537
     538        /**
     539         *
     540         * @return whether this is the public registry
     541         * @deprecated use {@link #getStatus() } to check if this is the
     542         *             {@link ComponentStatus#PUBLISHED public registry}
     543         */
     544        @Override
     545        @Deprecated
     546        public boolean isPublic() {
     547                return registryStatus == ComponentStatus.PUBLISHED;
     548        }
     549
     550        /**
     551         * @return The user id, or null if there is no owner or it is not a user.
     552         */
     553        private Number getUserId() {
     554                if (registryOwner instanceof OwnerUser) {
     555                        return registryOwner.getId();
     556                } else {
     557                        return null;
     558                }
     559        }
     560
     561        @Override
     562        public Owner getOwner() {
     563                return registryOwner;
     564        }
     565
     566        /**
     567         * Sets status and owner of this registry
     568         *
     569         * @param status
     570         *            new status for registry
     571         * @param owner
     572         *            new owner for registry
     573         */
     574        public void setStatus(ComponentStatus status, Owner owner) {
     575                setStatus(status);
     576                this.registryOwner = owner;
     577        }
     578
     579        public void setStatus(ComponentStatus status) {
     580                this.registryStatus = status;
     581        }
     582
     583        @Override
     584        public ComponentStatus getStatus() {
     585                return registryStatus;
     586        }
     587
     588        private void invalidateCache(AbstractDescription description) {
     589                if (description.isProfile()) {
     590                        profilesCache.remove(description.getId());
     591                } else {
     592                        componentsCache.remove(description.getId());
     593                }
     594        }
     595
     596        private AbstractDescriptionDao<?> getDaoForDescription(AbstractDescription description) {
     597                return description.isProfile() ? profileDescriptionDao : componentDescriptionDao;
     598        }
     599
     600        /**
     601         * Looks up description on basis of CMD Id. This will also check if such a
     602         * record even exists.
     603         *
     604         * @param description
     605         *            Description to look up
     606         * @return Database id for description
     607         * @throws IllegalArgumentException
     608         *             If description with non-existing id is passed
     609         */
     610        private Number getIdForDescription(AbstractDescription description) throws IllegalArgumentException {
     611                Number dbId = null;
     612                AbstractDescriptionDao<?> dao = getDaoForDescription(description);
     613                try {
     614                        dbId = dao.getDbId(description.getId());
     615                } catch (DataAccessException ex) {
     616                        LOG.error("Error getting dbId for component with id " + description.getId(), ex);
     617                }
     618                if (dbId == null) {
     619                        throw new IllegalArgumentException("Could not get database Id for description");
     620                } else {
     621                        return dbId;
     622                }
     623        }
     624
     625        private String componentSpecToString(CMDComponentSpec spec) throws UnsupportedEncodingException, JAXBException {
     626                ByteArrayOutputStream os = new ByteArrayOutputStream();
     627                getMarshaller().marshal(spec, os);
     628                String xml = os.toString("UTF-8");
     629                return xml;
     630        }
     631
     632        private CMDComponentSpec getUncachedMDComponent(String id, AbstractDescriptionDao dao) {
     633                String xml = dao.getContent(false, id);
     634                if (xml != null) {
     635                        try {
     636                                InputStream is = new ByteArrayInputStream(xml.getBytes("UTF-8"));
     637                                return getMarshaller().unmarshal(CMDComponentSpec.class, is, null);
     638
     639                        } catch (JAXBException ex) {
     640                                LOG.error("Error while unmarshalling", ex);
     641                        } catch (UnsupportedEncodingException ex) {
     642                                LOG.error("Exception while reading XML from database", ex);
     643                        }
     644                }
     645                return null;
     646        }
     647
     648        private void checkAuthorisation(AbstractDescription desc, Principal principal) throws UserUnauthorizedException {
     649                if (!isOwnerOfDescription(desc, principal.getName()) && !configuration.isAdminUser(principal)) {
     650                        throw new UserUnauthorizedException("Unauthorized operation user '" + principal.getName()
     651                                        + "' is not the creator (nor an administrator) of the "
     652                                        + (desc.isProfile() ? "profile" : "component") + "(" + desc + ").");
     653                }
     654        }
     655
     656        private void checkAuthorisationComment(Comment desc, Principal principal) throws UserUnauthorizedException {
     657                if (!isOwnerOfComment(desc, principal.getName()) && !configuration.isAdminUser(principal)) {
     658                        throw new UserUnauthorizedException("Unauthorized operation user '" + principal.getName()
     659                                        + "' is not the creator (nor an administrator) of the " + (desc.getId()) + "(" + desc + ").");
     660                }
     661        }
     662
     663        private boolean isOwnerOfDescription(AbstractDescription desc, String principalName) {
     664                String owner = getDaoForDescription(desc).getOwnerPrincipalName(getIdForDescription(desc));
     665                return owner != null // If owner is null, no one can be owner
     666                                && principalName.equals(owner);
     667        }
     668
     669        private boolean isOwnerOfComment(Comment com, String principalName) {
     670                String owner = commentsDao.getOwnerPrincipalName(Integer.parseInt(com.getId()));
     671                return owner != null // If owner is null, no one can be owner
     672                                && principalName.equals(owner);
     673        }
     674
     675        private void checkAge(AbstractDescription desc, Principal principal) throws DeleteFailedException {
     676                if (isPublic() && !configuration.isAdminUser(principal)) {
     677                        try {
     678                                Date regDate = AbstractDescription.getDate(desc.getRegistrationDate());
     679                                Calendar calendar = Calendar.getInstance();
     680                                calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1);
     681                                if (regDate.before(calendar.getTime())) { // More then month old
     682                                        throw new DeleteFailedException(
     683                                                        "The "
     684                                                                        + (desc.isProfile() ? "Profile" : "Component")
     685                                                                        + " is more then a month old and cannot be deleted anymore. It might have been used to create metadata, deleting it would invalidate that metadata.");
     686                                }
     687                        } catch (ParseException e) {
     688                                LOG.error("Cannot parse date of " + desc + " Error:" + e);
     689                        }
     690                }
     691        }
     692
     693        private boolean inWorkspace(AbstractDescriptionDao<?> dao, String cmdId) {
     694                if (isPublic()) {
     695                        return dao.isPublic(cmdId);
     696                } else {
     697                        return dao.isInUserSpace(cmdId, getUserId());
     698                }
     699        }
     700
     701        private boolean canCurrentUserAccessDescription(AbstractDescriptionDao<?> dao, String cmdId) {
     702                if (cmdId == null)
     703                        return false;
     704                RegistryUser user = userDao.getById(getUserId());
     705                if (user == null)
     706                        return false;
     707                AbstractDescription description = dao.getByCmdId(cmdId);
     708                if (description == null)
     709                        return false;
     710                if (cmdId.startsWith(ComponentDescription.COMPONENT_PREFIX)){
     711                        return groupService.canUserAccessComponentEitherOnHisOwnOrThroughGroupMembership(user, (ComponentDescription)description);
     712                }
     713                if (cmdId.startsWith(ProfileDescription.PROFILE_PREFIX)){
     714                        return groupService.canUserAccessProfileEitherOnHisOwnOrThroughGroupMembership(user, (ProfileDescription)description);
     715                }
     716                return false;
     717        }
     718       
     719        @Override
     720        public String getName() {
     721                if (isPublic()) {
     722                        return ComponentRegistry.PUBLIC_NAME;
     723                } else {
     724                        return "Registry of " + userDao.getById(getUserId()).getName();
     725                }
     726        }
     727
     728        @Override
     729        public List<ProfileDescription> getDeletedProfileDescriptions() {
     730                return profileDescriptionDao.getDeletedDescriptions(getUserId());
     731        }
     732
     733        @Override
     734        public List<ComponentDescription> getDeletedComponentDescriptions() {
     735                return componentDescriptionDao.getDeletedDescriptions(getUserId());
     736        }
     737
     738        @Override
     739        public void deleteComment(String commentId, Principal principal) throws IOException, ComponentRegistryException,
     740                        UserUnauthorizedException, DeleteFailedException {
     741                try {
     742                        Comment comment = commentsDao.getById(Integer.parseInt(commentId));
     743                        if (comment != null
     744                        // Comment must have an existing (in this registry)
     745                        // componentId or profileId
     746                                        && (comment.getComponentDescriptionId() != null
     747                                                        && componentDescriptionDao.isInRegistry(comment.getComponentDescriptionId(), getUserId()) || comment
     748                                                        .getProfileDescriptionId() != null
     749                                                        && profileDescriptionDao.isInRegistry(comment.getProfileDescriptionId(), getUserId()))) {
     750                                checkAuthorisationComment(comment, principal);
     751                                commentsDao.deleteComment(comment);
     752                        } else {
     753                                // Comment exists in DB, but component is not in this registry
     754                                throw new ComponentRegistryException("Comment " + commentId + " cannot be found in specified registry");
     755                        }
     756                } catch (DataAccessException ex) {
     757                        throw new DeleteFailedException("Database access error while trying to delete component", ex);
     758                } catch (NumberFormatException ex) {
     759                        throw new DeleteFailedException("Illegal comment ID, cannot parse integer", ex);
     760                }
     761        }
     762
     763        @Override
     764        public CMDComponentSpecExpander getExpander() {
     765                return new CMDComponentSpecExpanderDbImpl(this);
     766        }
     767
     768        @Override
     769        protected MDMarshaller getMarshaller() {
     770                return marshaller;
     771        }
     772
     773        @Override
     774        public String toString() {
     775                return getName();
     776        }
     777
     778        @Override
     779        public List<ComponentDescription> getComponentDescriptionsInGroup(String principalName, String groupId)
     780                        throws ComponentRegistryException {
     781                List<String> componentIds = groupService.getComponentIdsInGroup(Long.parseLong(groupId));
     782                List<ComponentDescription> components = new ArrayList<ComponentDescription>();
     783                for (String id : componentIds) {
     784                        ComponentDescription componentDescription = componentDescriptionDao.getByCmdId(id);
     785                        // minor robustness consideration: if, for whatever reason, the
     786                        // component for an ownership has been removed, don't return a null
     787                        // but just skip it
     788                        if (componentDescription != null)
     789                                components.add(componentDescription);
     790                }
     791                return components;
     792        }
     793
     794        @Override
     795        public List<ProfileDescription> getProfileDescriptionsForMetadaEditor(String groupId)
     796                        throws ComponentRegistryException {
     797                List<String> componentIds = groupService.getProfileIdsInGroup(Long.parseLong(groupId));
     798                List<ProfileDescription> profiles = new ArrayList<ProfileDescription>();
     799                for (String id : componentIds) {
     800                        ProfileDescription profile = getProfileDescription(id);
     801                        if (profile != null)
     802                                profiles.add(profile);
     803                }
     804                return profiles;
     805        }
     806
     807        @Override
     808        public List<ProfileDescription> getProfileDescriptionsInGroup(String groupId) throws ComponentRegistryException {
     809                List<String> componentIds = groupService.getProfileIdsInGroup(Long.parseLong(groupId));
     810                List<ProfileDescription> profiles = new ArrayList<ProfileDescription>();
     811                for (String id : componentIds)
     812                        profiles.add(profileDescriptionDao.getByCmdId(id));
     813                return profiles;
     814        }
    908815}
  • ComponentRegistry/branches/ComponentRegistry-1.14.0/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/impl/database/GroupServiceImpl.java

    r3893 r4168  
    4444public class GroupServiceImpl implements GroupService {
    4545
    46     @Autowired
    47     private GroupDao groupDao;
    48     @Autowired
    49     private GroupMembershipDao groupMembershipDao;
    50     @Autowired
    51     private OwnershipDao ownershipDao;
    52     @Autowired
    53     private ProfileDescriptionDao profileDescriptionDao;
    54     @Autowired
    55     private ComponentDescriptionDao componentDescriptionDao;
    56     @Autowired
    57     private UserDao userDao;
    58 
    59     public void setGroupDao(GroupDao groupDao) {
    60         this.groupDao = groupDao;
    61     }
    62 
    63     public void setGroupMembershipDao(GroupMembershipDao groupMembershipDao) {
    64         this.groupMembershipDao = groupMembershipDao;
    65     }
    66 
    67     public void setOwnershipDao(OwnershipDao ownershipDao) {
    68         this.ownershipDao = ownershipDao;
    69     }
    70 
    71     @Override
    72     public List<Group> getGroupsOwnedByUser(String ownerPrincipalName) {
    73         RegistryUser owner = userDao.getByPrincipalName(ownerPrincipalName);
    74         return groupDao.findGroupOwnedByUser(owner.getId().longValue());
    75     }
    76 
    77     @Override
    78     public boolean isUserOwnerOfGroup(long groupId, RegistryUser user) {
    79         List<Group> groups = getGroupsOwnedByUser(user.getPrincipalName());
    80         for (Group group : groups)
    81             if (group.getId() == groupId)
    82                 return true;
    83         return false;
    84     }
    85 
    86     private void checkOwnership(Ownership ownership) {
    87         if (ownership.getComponentId() == null
    88                 && ownership.getProfileId() == null)
    89             throw new RuntimeException(
    90                     "Ownership needs either a componentId or a profileId");
    91         if (ownership.getComponentId() != null
    92                 && ownership.getProfileId() != null)
    93             throw new RuntimeException(
    94                     "Ownership has both a componentId and a profileId");
    95         if (ownership.getUserId() == 0 && ownership.getGroupId() == 0)
    96             throw new RuntimeException("Ownership needs a groupId or userId");
    97         if (ownership.getUserId() != 0 && ownership.getGroupId() != 0)
    98             throw new RuntimeException(
    99                     "Ownership has both a groupId and a userId ");
    100     }
    101 
    102     private void assertOwnershipDoesNotExist(Ownership ownership) {
    103         Ownership o = ownershipDao.findOwnershipByGroupAndComponent(
    104                 ownership.getGroupId(), ownership.getComponentId());
    105         if (o != null)
    106             throw new ValidationException("Ownership exists");
    107         o = ownershipDao.findOwnershipByGroupAndProfile(ownership.getGroupId(),
    108                 ownership.getProfileId());
    109         if (o != null)
    110             throw new ValidationException("Ownership exists");
    111         o = ownershipDao.findOwnershipByUserAndProfile(ownership.getUserId(),
    112                 ownership.getProfileId());
    113         if (o != null)
    114             throw new ValidationException("Ownership exists");
    115         // o =
    116         // ownershipDao.findOwnershipByUserAndComponent(ownership.getUserId(),
    117         // ownership.getComponentId());
    118         // if (o != null)
    119         // throw new ValidationException("Ownership exists");
    120     }
    121 
    122     @Override
    123     public void addOwnership(Ownership ownership) {
    124         checkOwnership(ownership);
    125         assertOwnershipDoesNotExist(ownership);
    126         ownershipDao.save(ownership);
    127     }
    128 
    129     @Override
    130     public void removeOwnership(Ownership ownership) {
    131         throw new RuntimeException("not implemented");
    132     }
    133 
    134     protected boolean canUserAccessAbstractDescriptionEitherOnHisOwnOrThroughGroupMembership(
    135             RegistryUser user, AbstractDescription description) {
    136         // TODO make some joins and multi-id queries to speed the entire method
    137         // up
    138         boolean isProfile = (description instanceof ProfileDescription);
    139         AbstractDescriptionDao<? extends AbstractDescription> dao = isProfile ? profileDescriptionDao
    140                 : componentDescriptionDao;
    141         long userId = user.getId().longValue();
    142         // anyone can access public profile
    143         if (dao.isPublic(description.getId()))
    144             return true;
    145         // the creator can also access any profile
    146         if (description.getUserId().equals(user.getId() + ""))
    147             return true;
    148 
    149         // a co-ownership on the profile also allows access
    150         Ownership ownership = isProfile ? ownershipDao
    151                 .findOwnershipByUserAndProfile(userId, description.getId())
    152                 : ownershipDao.findOwnershipByUserAndComponent(userId,
    153                         description.getId());
    154         if (ownership != null)
    155             return true;
    156 
    157         // get a list of groups the user owns and is a member of
    158         List<Group> groups = groupDao.findGroupOwnedByUser(userId);
    159         Set<Long> groupIds = new HashSet<Long>();
    160         for (Group group : groups)
    161             groupIds.add(group.getId());
    162 
    163         List<GroupMembership> memberships = groupMembershipDao
    164                 .findGroupsTheUserIsAmemberOf(userId);
    165         for (GroupMembership gm : memberships)
    166             groupIds.add(gm.getGroupId());
    167 
    168         for (Long groupId : groupIds) {
    169             ownership = isProfile ? ownershipDao
    170                     .findOwnershipByGroupAndProfile(groupId,
    171                             description.getId()) : ownershipDao
    172                     .findOwnershipByGroupAndComponent(groupId,
    173                             description.getId());
    174             if (ownership != null)
    175                 return true;
    176         }
    177         return false;
    178     }
    179 
    180     @Override
    181     public boolean canUserAccessProfileEitherOnHisOwnOrThroughGroupMembership(
    182             RegistryUser user, ProfileDescription profile) {
    183         return canUserAccessAbstractDescriptionEitherOnHisOwnOrThroughGroupMembership(
    184                 user, profile);
    185     }
    186 
    187     @Override
    188     public boolean canUserAccessComponentEitherOnHisOwnOrThroughGroupMembership(
    189             RegistryUser user, ComponentDescription component) {
    190         return canUserAccessAbstractDescriptionEitherOnHisOwnOrThroughGroupMembership(
    191                 user, component);
    192     }
    193 
    194     @Override
    195     @ManagedOperation(description = "Mage a user member of a group")
    196     @ManagedOperationParameters({
    197             @ManagedOperationParameter(name = "principalName", description = "Principal name of the user to make a member"),
    198             @ManagedOperationParameter(name = "groupName", description = "Name of the group") })
    199     public long makeMember(String userPrincipalName, String groupName) {
    200         RegistryUser user = userDao.getByPrincipalName(userPrincipalName);
    201         Group group = groupDao.findGroupByName(groupName);
    202         GroupMembership gm = groupMembershipDao.findMembership(user.getId()
    203                 .longValue(), group.getId());
    204         if (gm != null)
    205             return gm.getId();
    206         gm = new GroupMembership();
    207         gm.setGroupId(group.getId());
    208         gm.setUserId(user.getId().longValue());
    209         return groupMembershipDao.save(gm).getId();
    210     }
    211 
    212     @ManagedOperation(description = "Create a new group")
    213     @ManagedOperationParameters({
    214             @ManagedOperationParameter(name = "name", description = "Name of the group, must be unique"),
    215             @ManagedOperationParameter(name = "ownerPrincipalName", description = "Principal name of the user") })
    216     @Override
    217     public long createNewGroup(String name, String ownerPrincipalName) {
    218         RegistryUser owner = userDao.getByPrincipalName(ownerPrincipalName);
    219         if (owner == null)
    220             throw new ValidationException("No principal '" + ownerPrincipalName
    221                     + "' found");
    222         Group group = groupDao.findGroupByName(name);
    223         if (group != null)
    224             throw new ValidationException("Group '" + name + "' already exists");
    225         group = new Group();
    226         group.setName(name);
    227         group.setOwnerId(owner.getId().longValue());
    228         group = groupDao.save(group);
    229         return group.getId();
    230     }
    231 
    232     @ManagedOperation(description = "List available groups")
    233     @Override
    234     public List<String> listGroupNames() {
    235         List<String> groupNames = new ArrayList<String>();
    236         for (Group group : groupDao.findAll())
    237             groupNames.add(group.getName());
    238         return groupNames;
    239     }
    240 
    241     protected void transferAbstractDescriptionOwnershipFromUserToGroup(
    242             String principal, String groupName, String descriptionId,
    243             boolean isProfile) {
    244         RegistryUser user = userDao.getByPrincipalName(principal);
    245         Group group = groupDao.findGroupByName(groupName);
    246         Ownership ownership = null;
    247         List<Ownership> oldOwnerships = isProfile ? ownershipDao
    248                 .findOwnershipByProfileId(descriptionId) : ownershipDao
    249                 .findOwnershipByComponentId(descriptionId);
    250         ownershipDao.delete(oldOwnerships);
    251         ownership = new Ownership();
    252         if (isProfile)
    253             ownership.setProfileId(descriptionId);
    254         else
    255             ownership.setComponentId(descriptionId);
    256         ownership.setGroupId(group.getId());
    257         addOwnership(ownership);
    258     }
    259 
    260     @ManagedOperation(description = "Make a component owned by a group instead of a user")
    261     @ManagedOperationParameters({
    262             @ManagedOperationParameter(name = "principal", description = "Name of the principal who owns the component"),
    263             @ManagedOperationParameter(name = "groupName", description = "Name of the group to move the component to"),
    264             @ManagedOperationParameter(name = "componentId", description = "Id of component") })
    265     @Override
    266     public void transferComponentOwnershipFromUserToGroup(String principal,
    267             String groupName, String componentId) {
    268         transferAbstractDescriptionOwnershipFromUserToGroup(principal,
    269                 groupName, componentId, false);
    270     }
    271 
    272     @ManagedOperation(description = "Make a profile owned by a group instead of a user")
    273     @ManagedOperationParameters({
    274             @ManagedOperationParameter(name = "principal", description = "Name of the principal who owns the profile"),
    275             @ManagedOperationParameter(name = "groupName", description = "Name of the group to move the profile to"),
    276             @ManagedOperationParameter(name = "componentId", description = "Id of profile") })
    277     @Override
    278     public void transferProfileOwnershipFromUserToGroup(String principal,
    279             String groupName, String profileId) {
    280         transferAbstractDescriptionOwnershipFromUserToGroup(principal,
    281                 groupName, profileId, true);
    282     }
    283 
    284     @Override
    285     public List<Group> getGroupsOfWhichUserIsAMember(String principal) {
    286         RegistryUser user = userDao.getByPrincipalName(principal);
    287         if (user == null || user.getId() == null)
    288             return new ArrayList<Group>();
    289         List<GroupMembership> memberships = groupMembershipDao
    290                 .findGroupsTheUserIsAmemberOf(user.getId().longValue());
    291         List<Group> groups = new ArrayList<Group>();
    292         for (GroupMembership m : memberships)
    293             groups.add(groupDao.findOne(m.getGroupId()));
    294         return groups;
    295       }
    296 
    297     @Override
    298     public List<String> getComponentIdsInGroup(long groupId) {
    299         List<Ownership> ownerships = ownershipDao.findOwnershipByGroup(groupId);
    300         Set<String> componentIds = new HashSet<String>();
    301         for (Ownership o : ownerships)
    302             if (o.getComponentId() != null)
    303                 componentIds.add(o.getComponentId());
    304         List<String> idsList = new ArrayList<String>(componentIds);
    305         Collections.sort(idsList);
    306         return idsList;
    307     }
    308 
    309     @Override
    310     public List<String> getProfileIdsInGroup(long groupId) {
    311         List<Ownership> ownerships = ownershipDao.findOwnershipByGroup(groupId);
    312         Set<String> profileIds = new HashSet<String>();
    313         for (Ownership o : ownerships)
    314             if (o.getProfileId() != null)
    315                 profileIds.add(o.getProfileId());
    316         List<String> idsList = new ArrayList<String>(profileIds);
    317         Collections.sort(idsList);
    318         return idsList;
    319     }
    320 
    321     @Override
    322     public List<Group> getGroupsTheItemIsAMemberOf(String itemId) {
    323         Set<Ownership> ownerships = new HashSet<Ownership>();
    324         ownerships.addAll(ownershipDao.findOwnershipByProfileId(itemId));
    325         ownerships.addAll(ownershipDao.findOwnershipByComponentId(itemId));
    326         Set<Group> groups = new HashSet<Group>();
    327         for (Ownership ownership : ownerships)
    328             groups.add(groupDao.findOne(ownership.getGroupId()));
    329         List<Group> groupList = new ArrayList<Group>(groups);
    330         Collections.sort(groupList, new Comparator<Group>() {
    331 
    332             @Override
    333             public int compare(Group g1, Group g2) {
    334                 return (int) (g1.getId() - g2.getId());
    335             }
    336         });
    337         return groupList;
    338     }
    339 
    340     @Override
    341     public void transferItemOwnershipFromUserToGroup(String principal,
    342             long groupId, String itemId) {
    343 
    344         AbstractDescription item = null;
    345         item = profileDescriptionDao.getByCmdId(itemId);
    346         boolean isProfile = true;
    347         if (item == null) {
    348             item = componentDescriptionDao.getByCmdId(itemId);
    349             isProfile = false;
    350         }
    351         if (item == null)
    352             throw new ValidationException(
    353                     "No profile or component found with ID " + itemId);
    354         Group group = groupDao.findOne(groupId);
    355         if (group == null)
    356             throw new ValidationException("No group found with ID " + groupId);
    357         String groupName = group.getName();
    358         if (isProfile)
    359             transferProfileOwnershipFromUserToGroup(principal, groupName,
    360                     item.getId());
    361         else
    362             transferComponentOwnershipFromUserToGroup(principal, groupName,
    363                     item.getId());
    364     }
     46        @Autowired
     47        private GroupDao groupDao;
     48        @Autowired
     49        private GroupMembershipDao groupMembershipDao;
     50        @Autowired
     51        private OwnershipDao ownershipDao;
     52        @Autowired
     53        private ProfileDescriptionDao profileDescriptionDao;
     54        @Autowired
     55        private ComponentDescriptionDao componentDescriptionDao;
     56        @Autowired
     57        private UserDao userDao;
     58
     59        public void setGroupDao(GroupDao groupDao) {
     60                this.groupDao = groupDao;
     61        }
     62
     63        public void setGroupMembershipDao(GroupMembershipDao groupMembershipDao) {
     64                this.groupMembershipDao = groupMembershipDao;
     65        }
     66
     67        public void setOwnershipDao(OwnershipDao ownershipDao) {
     68                this.ownershipDao = ownershipDao;
     69        }
     70
     71        @Override
     72        public List<Group> getGroupsOwnedByUser(String ownerPrincipalName) {
     73                RegistryUser owner = userDao.getByPrincipalName(ownerPrincipalName);
     74                return groupDao.findGroupOwnedByUser(owner.getId().longValue());
     75        }
     76
     77        @Override
     78        public boolean isUserOwnerOfGroup(long groupId, RegistryUser user) {
     79                List<Group> groups = getGroupsOwnedByUser(user.getPrincipalName());
     80                for (Group group : groups)
     81                        if (group.getId() == groupId)
     82                                return true;
     83                return false;
     84        }
     85
     86        private void checkOwnership(Ownership ownership) {
     87                if (ownership.getComponentId() == null && ownership.getProfileId() == null)
     88                        throw new RuntimeException("Ownership needs either a componentId or a profileId");
     89                if (ownership.getComponentId() != null && ownership.getProfileId() != null)
     90                        throw new RuntimeException("Ownership has both a componentId and a profileId");
     91                if (ownership.getUserId() == 0 && ownership.getGroupId() == 0)
     92                        throw new RuntimeException("Ownership needs a groupId or userId");
     93                if (ownership.getUserId() != 0 && ownership.getGroupId() != 0)
     94                        throw new RuntimeException("Ownership has both a groupId and a userId ");
     95        }
     96
     97        private void assertOwnershipDoesNotExist(Ownership ownership) {
     98                Ownership o = ownershipDao.findOwnershipByGroupAndComponent(ownership.getGroupId(), ownership.getComponentId());
     99                if (o != null)
     100                        throw new ValidationException("Ownership exists");
     101                o = ownershipDao.findOwnershipByGroupAndProfile(ownership.getGroupId(), ownership.getProfileId());
     102                if (o != null)
     103                        throw new ValidationException("Ownership exists");
     104                o = ownershipDao.findOwnershipByUserAndProfile(ownership.getUserId(), ownership.getProfileId());
     105                if (o != null)
     106                        throw new ValidationException("Ownership exists");
     107                // o =
     108                // ownershipDao.findOwnershipByUserAndComponent(ownership.getUserId(),
     109                // ownership.getComponentId());
     110                // if (o != null)
     111                // throw new ValidationException("Ownership exists");
     112        }
     113
     114        @Override
     115        public void addOwnership(Ownership ownership) {
     116                checkOwnership(ownership);
     117                assertOwnershipDoesNotExist(ownership);
     118                ownershipDao.save(ownership);
     119        }
     120
     121        @Override
     122        public void removeOwnership(Ownership ownership) {
     123                throw new RuntimeException("not implemented");
     124        }
     125
     126        protected boolean canUserAccessAbstractDescriptionEitherOnHisOwnOrThroughGroupMembership(RegistryUser user,
     127                        AbstractDescription description) {
     128                // TODO make some joins and multi-id queries to speed the entire method
     129                // up
     130                boolean isProfile = (description instanceof ProfileDescription);
     131                AbstractDescriptionDao<? extends AbstractDescription> dao = isProfile ? profileDescriptionDao
     132                                : componentDescriptionDao;
     133                long userId = user.getId().longValue();
     134                // anyone can access public profile
     135                if (dao.isPublic(description.getId()))
     136                        return true;
     137                // the creator can also access any profile
     138                if (description.getUserId().equals(user.getId() + ""))
     139                        return true;
     140
     141                // a co-ownership on the profile also allows access
     142                Ownership ownership = isProfile ? ownershipDao.findOwnershipByUserAndProfile(userId, description.getId())
     143                                : ownershipDao.findOwnershipByUserAndComponent(userId, description.getId());
     144                if (ownership != null)
     145                        return true;
     146
     147                // get a list of groups the user owns and is a member of
     148                List<Group> groups = groupDao.findGroupOwnedByUser(userId);
     149                Set<Long> groupIds = new HashSet<Long>();
     150                for (Group group : groups)
     151                        groupIds.add(group.getId());
     152
     153                List<GroupMembership> memberships = groupMembershipDao.findGroupsTheUserIsAmemberOf(userId);
     154                for (GroupMembership gm : memberships)
     155                        groupIds.add(gm.getGroupId());
     156
     157                for (Long groupId : groupIds) {
     158                        ownership = isProfile ? ownershipDao.findOwnershipByGroupAndProfile(groupId, description.getId())
     159                                        : ownershipDao.findOwnershipByGroupAndComponent(groupId, description.getId());
     160                        if (ownership != null)
     161                                return true;
     162                }
     163                return false;
     164        }
     165
     166        @Override
     167        public boolean canUserAccessProfileEitherOnHisOwnOrThroughGroupMembership(RegistryUser user,
     168                        ProfileDescription profile) {
     169                return canUserAccessAbstractDescriptionEitherOnHisOwnOrThroughGroupMembership(user, profile);
     170        }
     171
     172        @Override
     173        public boolean canUserAccessComponentEitherOnHisOwnOrThroughGroupMembership(RegistryUser user,
     174                        ComponentDescription component) {
     175                return canUserAccessAbstractDescriptionEitherOnHisOwnOrThroughGroupMembership(user, component);
     176        }
     177
     178        @Override
     179        @ManagedOperation(description = "Make a user member of a group")
     180        @ManagedOperationParameters({
     181                        @ManagedOperationParameter(name = "principalName", description = "Principal name of the user to make a member"),
     182                        @ManagedOperationParameter(name = "groupName", description = "Name of the group") })
     183        public long makeMember(String userPrincipalName, String groupName) {
     184                RegistryUser user = userDao.getByPrincipalName(userPrincipalName);
     185                Group group = groupDao.findGroupByName(groupName);
     186                GroupMembership gm = groupMembershipDao.findMembership(user.getId().longValue(), group.getId());
     187                if (gm != null)
     188                        return gm.getId();
     189                gm = new GroupMembership();
     190                gm.setGroupId(group.getId());
     191                gm.setUserId(user.getId().longValue());
     192                return groupMembershipDao.save(gm).getId();
     193        }
     194
     195        @ManagedOperation(description = "Create a new group")
     196        @ManagedOperationParameters({
     197                        @ManagedOperationParameter(name = "name", description = "Name of the group, must be unique"),
     198                        @ManagedOperationParameter(name = "ownerPrincipalName", description = "Principal name of the user") })
     199        @Override
     200        public long createNewGroup(String name, String ownerPrincipalName) {
     201                RegistryUser owner = userDao.getByPrincipalName(ownerPrincipalName);
     202                if (owner == null)
     203                        throw new ValidationException("No principal '" + ownerPrincipalName + "' found");
     204                Group group = groupDao.findGroupByName(name);
     205                if (group != null)
     206                        throw new ValidationException("Group '" + name + "' already exists");
     207                group = new Group();
     208                group.setName(name);
     209                group.setOwnerId(owner.getId().longValue());
     210                group = groupDao.save(group);
     211                return group.getId();
     212        }
     213
     214        @ManagedOperation(description = "List available groups")
     215        @Override
     216        public List<String> listGroupNames() {
     217                List<String> groupNames = new ArrayList<String>();
     218                for (Group group : groupDao.findAll())
     219                        groupNames.add(group.getName());
     220                return groupNames;
     221        }
     222
     223        protected void transferAbstractDescriptionOwnershipFromUserToGroup(String principal, String groupName,
     224                        String descriptionId, boolean isProfile) {
     225                RegistryUser user = userDao.getByPrincipalName(principal);
     226                Group group = groupDao.findGroupByName(groupName);
     227                Ownership ownership = null;
     228                List<Ownership> oldOwnerships = isProfile ? ownershipDao.findOwnershipByProfileId(descriptionId) : ownershipDao
     229                                .findOwnershipByComponentId(descriptionId);
     230                ownershipDao.delete(oldOwnerships);
     231                ownership = new Ownership();
     232                if (isProfile)
     233                        ownership.setProfileId(descriptionId);
     234                else
     235                        ownership.setComponentId(descriptionId);
     236                ownership.setGroupId(group.getId());
     237                addOwnership(ownership);
     238        }
     239
     240        @ManagedOperation(description = "Make a component owned by a group instead of a user")
     241        @ManagedOperationParameters({
     242                        @ManagedOperationParameter(name = "principal", description = "Name of the principal who owns the component"),
     243                        @ManagedOperationParameter(name = "groupName", description = "Name of the group to move the component to"),
     244                        @ManagedOperationParameter(name = "componentId", description = "Id of component") })
     245        @Override
     246        public void transferComponentOwnershipFromUserToGroup(String principal, String groupName, String componentId) {
     247                transferAbstractDescriptionOwnershipFromUserToGroup(principal, groupName, componentId, false);
     248        }
     249
     250        @ManagedOperation(description = "Make a profile owned by a group instead of a user")
     251        @ManagedOperationParameters({
     252                        @ManagedOperationParameter(name = "principal", description = "Name of the principal who owns the profile"),
     253                        @ManagedOperationParameter(name = "groupName", description = "Name of the group to move the profile to"),
     254                        @ManagedOperationParameter(name = "componentId", description = "Id of profile") })
     255        @Override
     256        public void transferProfileOwnershipFromUserToGroup(String principal, String groupName, String profileId) {
     257                transferAbstractDescriptionOwnershipFromUserToGroup(principal, groupName, profileId, true);
     258        }
     259
     260        @Override
     261        public List<Group> getGroupsOfWhichUserIsAMember(String principal) {
     262                RegistryUser user = userDao.getByPrincipalName(principal);
     263                if (user == null || user.getId() == null)
     264                        return new ArrayList<Group>();
     265                List<GroupMembership> memberships = groupMembershipDao.findGroupsTheUserIsAmemberOf(user.getId().longValue());
     266                List<Group> groups = new ArrayList<Group>();
     267                for (GroupMembership m : memberships)
     268                        groups.add(groupDao.findOne(m.getGroupId()));
     269                return groups;
     270        }
     271
     272        @Override
     273        public List<String> getComponentIdsInGroup(long groupId) {
     274                List<Ownership> ownerships = ownershipDao.findOwnershipByGroup(groupId);
     275                Set<String> componentIds = new HashSet<String>();
     276                for (Ownership o : ownerships)
     277                        if (o.getComponentId() != null)
     278                                componentIds.add(o.getComponentId());
     279                List<String> idsList = new ArrayList<String>(componentIds);
     280                Collections.sort(idsList);
     281                return idsList;
     282        }
     283
     284        @Override
     285        public List<String> getProfileIdsInGroup(long groupId) {
     286                List<Ownership> ownerships = ownershipDao.findOwnershipByGroup(groupId);
     287                Set<String> profileIds = new HashSet<String>();
     288                for (Ownership o : ownerships)
     289                        if (o.getProfileId() != null)
     290                                profileIds.add(o.getProfileId());
     291                List<String> idsList = new ArrayList<String>(profileIds);
     292                Collections.sort(idsList);
     293                return idsList;
     294        }
     295
     296        @Override
     297        public List<Group> getGroupsTheItemIsAMemberOf(String itemId) {
     298                Set<Ownership> ownerships = new HashSet<Ownership>();
     299                ownerships.addAll(ownershipDao.findOwnershipByProfileId(itemId));
     300                ownerships.addAll(ownershipDao.findOwnershipByComponentId(itemId));
     301                Set<Group> groups = new HashSet<Group>();
     302                for (Ownership ownership : ownerships)
     303                        groups.add(groupDao.findOne(ownership.getGroupId()));
     304                List<Group> groupList = new ArrayList<Group>(groups);
     305                Collections.sort(groupList, new Comparator<Group>() {
     306
     307                        @Override
     308                        public int compare(Group g1, Group g2) {
     309                                return (int) (g1.getId() - g2.getId());
     310                        }
     311                });
     312                return groupList;
     313        }
     314
     315        @Override
     316        public void transferItemOwnershipFromUserToGroup(String principal, long groupId, String itemId) {
     317
     318                AbstractDescription item = null;
     319                item = profileDescriptionDao.getByCmdId(itemId);
     320                boolean isProfile = true;
     321                if (item == null) {
     322                        item = componentDescriptionDao.getByCmdId(itemId);
     323                        isProfile = false;
     324                }
     325                if (item == null)
     326                        throw new ValidationException("No profile or component found with ID " + itemId);
     327                Group group = groupDao.findOne(groupId);
     328                if (group == null)
     329                        throw new ValidationException("No group found with ID " + groupId);
     330                String groupName = group.getName();
     331                if (isProfile)
     332                        transferProfileOwnershipFromUserToGroup(principal, groupName, item.getId());
     333                else
     334                        transferComponentOwnershipFromUserToGroup(principal, groupName, item.getId());
     335        }
    365336
    366337}
Note: See TracChangeset for help on using the changeset viewer.