Ignore:
Timestamp:
08/11/14 16:07:55 (10 years ago)
Author:
olhsha@mpi.nl
Message:

Added group service. Tested via the tomcat on loclahots (test URI and postman), old unit tests are adjusted and work well. Todo: retest on localhost tomcat, look at run-time exceptions, add new unit tests, adjust front-end

File:
1 edited

Legend:

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

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