Changeset 5549 for ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/impl/database/ComponentRegistryDbImpl.java
- Timestamp:
- 08/11/14 16:07:55 (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
ComponentRegistry/trunk/ComponentRegistry/src/main/java/clarin/cmdi/componentregistry/impl/database/ComponentRegistryDbImpl.java
r4190 r5549 4 4 import clarin.cmdi.componentregistry.ComponentRegistry; 5 5 import clarin.cmdi.componentregistry.ComponentRegistryException; 6 import clarin.cmdi.componentregistry.ComponentStatus;7 6 import clarin.cmdi.componentregistry.Configuration; 8 7 import clarin.cmdi.componentregistry.DeleteFailedException; 8 import clarin.cmdi.componentregistry.ItemNotFoundException; 9 9 import clarin.cmdi.componentregistry.MDMarshaller; 10 10 import clarin.cmdi.componentregistry.Owner; 11 11 import clarin.cmdi.componentregistry.OwnerUser; 12 import clarin.cmdi.componentregistry.RegistrySpace; 12 13 import clarin.cmdi.componentregistry.UserUnauthorizedException; 13 14 import clarin.cmdi.componentregistry.components.CMDComponentSpec; 15 import clarin.cmdi.componentregistry.components.CMDComponentType; 14 16 import clarin.cmdi.componentregistry.impl.ComponentRegistryImplBase; 15 17 import clarin.cmdi.componentregistry.impl.ComponentUtils; … … 17 19 import clarin.cmdi.componentregistry.model.Comment; 18 20 import clarin.cmdi.componentregistry.model.ComponentDescription; 21 import clarin.cmdi.componentregistry.model.Group; 19 22 import clarin.cmdi.componentregistry.model.ProfileDescription; 20 23 import clarin.cmdi.componentregistry.model.RegistryUser; … … 30 33 import java.io.UnsupportedEncodingException; 31 34 import java.security.Principal; 32 import java.text.ParseException;33 35 import java.util.ArrayList; 34 36 import java.util.Calendar; … … 51 53 * Implementation of ComponentRegistry that uses Database Acces Objects for 52 54 * accessing the registry (ergo: a database implementation) 53 * 55 * 54 56 * @author Twan Goosen <twan.goosen@mpi.nl> 55 57 * @author George.Georgovassilis@mpi.nl … … 58 60 public class ComponentRegistryDbImpl extends ComponentRegistryImplBase implements ComponentRegistry { 59 61 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 } 805 972 }
Note: See TracChangeset
for help on using the changeset viewer.