06e2e2cc896ddbdd07dece5758e2afcfda37fbb4
[cdm-vaadin.git] / src / main / java / eu / etaxonomy / cdm / service / CdmStore.java
1 /**
2 * Copyright (C) 2017 EDIT
3 * European Distributed Institute of Taxonomy
4 * http://www.e-taxonomy.eu
5 *
6 * The contents of this file are subject to the Mozilla Public License Version 1.1
7 * See LICENSE.TXT at the top of this package for the full license terms.
8 */
9 package eu.etaxonomy.cdm.service;
10
11 import org.apache.logging.log4j.LogManager;
12 import org.apache.logging.log4j.Logger;
13 import org.hibernate.Session;
14 import org.springframework.beans.factory.annotation.Autowired;
15 import org.springframework.beans.factory.annotation.Qualifier;
16 import org.springframework.transaction.TransactionStatus;
17
18 import com.vaadin.spring.annotation.SpringComponent;
19 import com.vaadin.spring.annotation.ViewScope;
20 import com.vaadin.ui.Notification;
21 import com.vaadin.ui.UI;
22
23 import eu.etaxonomy.cdm.api.application.CdmRepository;
24 import eu.etaxonomy.cdm.api.service.DeleteResult;
25 import eu.etaxonomy.cdm.api.service.IService;
26 import eu.etaxonomy.cdm.model.agent.AgentBase;
27 import eu.etaxonomy.cdm.model.common.CdmBase;
28 import eu.etaxonomy.cdm.model.common.IdentifiableEntity;
29 import eu.etaxonomy.cdm.model.name.NameTypeDesignation;
30 import eu.etaxonomy.cdm.model.name.Registration;
31 import eu.etaxonomy.cdm.model.name.TaxonName;
32 import eu.etaxonomy.cdm.model.occurrence.Collection;
33 import eu.etaxonomy.cdm.model.occurrence.SpecimenOrObservationBase;
34 import eu.etaxonomy.cdm.model.reference.Reference;
35 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent;
36 import eu.etaxonomy.cdm.vaadin.event.EntityChangeEvent.Type;
37 import eu.etaxonomy.vaadin.mvp.AbstractView;
38
39 /**
40 * @author a.kohlbecker
41 * @since Jun 26, 2017
42 *
43 * TODO better naming of this class, ServiceWrapper, ServiceOperator, ...?
44 *
45 */
46 @SpringComponent
47 @ViewScope
48 public class CdmStore {
49
50 private static final Logger logger = LogManager.getLogger();
51
52 @Autowired
53 @Qualifier("cdmRepository")
54 private CdmRepository repo;
55
56 protected String _toString() {
57 return this.getClass().getSimpleName() + "@" + this.hashCode();
58 }
59
60 /**
61 *
62 * @param bean
63 *
64 * @return the merged bean, this bean is <b>not reloaded</b> from the
65 * persistent storage.
66 */
67 public <T extends CdmBase> EntityChangeEvent saveBean(T bean, AbstractView view) {
68
69 Type changeEventType;
70 if(bean.isPersited()){
71 changeEventType = Type.MODIFIED;
72 } else {
73 changeEventType = Type.CREATED;
74 }
75
76 try{
77 TransactionStatus txStatus = repo.startTransaction();
78 Session session = repo.getSession();
79 try {
80 logger.trace(this._toString() + ".onEditorSaveEvent - merging bean into session");
81 // merge the changes into the session, ...
82 if (session.contains(bean)) {
83 // evict bean before merge to avoid duplicate beans in same session
84 logger.trace(this._toString() + ".mergedBean() - evict " + bean.toString());
85 session.evict(bean);
86 }
87 logger.trace(this._toString() + ".mergedBean() - doing merge of" + bean.toString());
88 @SuppressWarnings("unchecked")
89 T mergedBean = (T) session.merge(bean);
90 repo.commitTransaction(txStatus);
91 return new EntityChangeEvent(mergedBean, changeEventType, view);
92 } catch(Exception e){
93 transactionRollbackIfNotCompleted(txStatus);
94 throw e;
95 }
96 } finally {
97 repo.clearSession(); // #7559
98 }
99
100 }
101
102
103 /**
104 * @param txStatus
105 */
106 public void transactionRollbackIfNotCompleted(TransactionStatus txStatus) {
107 if(!txStatus.isCompleted()){
108 repo.getTransactionManager().rollback(txStatus);
109 }
110 }
111
112 /**
113 *
114 * @param bean
115 * @return a EntityChangeEvent in case the deletion was successful otherwise <code>null</code>.
116 */
117 public final <T extends CdmBase> EntityChangeEvent deleteBean(T bean, AbstractView view) {
118
119 IService<T> typeSpecificService = serviceFor(bean);
120
121 try{
122 logger.trace(this._toString() + ".deleteBean - deleting" + bean.toString());
123 DeleteResult result = typeSpecificService.delete(bean);
124 if (result.isOk()) {
125 return new EntityChangeEvent(bean, Type.REMOVED, view);
126 } else {
127 handleDeleteresultInError(result);
128 }
129 } finally {
130 repo.clearSession(); // #7559
131 }
132
133 return null;
134 }
135
136 /**
137 * @param result
138 */
139 public static void handleDeleteresultInError(DeleteResult result) {
140 String notificationTitle;
141 StringBuffer messageBody = new StringBuffer();
142 if (result.isAbort()) {
143 notificationTitle = "The delete operation as abborded by the system.";
144 } else {
145 notificationTitle = "An error occured during the delete operation.";
146 }
147 if (!result.getExceptions().isEmpty()) {
148 messageBody.append("<h3>").append("Exceptions:").append("</h3>").append("<ul>");
149 result.getExceptions().forEach(e -> messageBody.append("<li>").append(e.getMessage()).append("</li>"));
150 messageBody.append("</ul>");
151 }
152 if (!result.getRelatedObjects().isEmpty()) {
153 messageBody.append("<h3>").append("Related objects exist:").append("</h3>").append("<ul>");
154 result.getRelatedObjects().forEach(e -> {
155 messageBody.append("<li>");
156 if (IdentifiableEntity.class.isAssignableFrom(e.getClass())) {
157 messageBody.append(((IdentifiableEntity) e).getTitleCache());
158 } else {
159 messageBody.append(e.toString());
160 }
161 messageBody.append("</li>");
162 });
163
164 messageBody.append("</ul>");
165 }
166 Notification notification = new Notification(notificationTitle, messageBody.toString(),
167 com.vaadin.ui.Notification.Type.ERROR_MESSAGE, true);
168 notification.show(UI.getCurrent().getPage());
169 }
170
171 @SuppressWarnings("unchecked")
172 protected <T extends CdmBase> IService<T> serviceFor(T bean){
173 Class<? extends CdmBase> cdmType = bean.getClass();
174
175 if(Registration.class.isAssignableFrom(cdmType)){
176 return (IService<T>) repo.getRegistrationService();
177 } else if(TaxonName.class.isAssignableFrom(cdmType)){
178 return (IService<T>) repo.getNameService();
179 } else if(Reference.class.isAssignableFrom(cdmType)){
180 return (IService<T>) repo.getReferenceService();
181 } else if (NameTypeDesignation.class.isAssignableFrom(cdmType)){
182 throw new RuntimeException("no generic sercvice for NameTypeDesignation, use dedicated methods of NameService");
183 } else if (SpecimenOrObservationBase.class.isAssignableFrom(cdmType)){
184 return (IService<T>) repo.getOccurrenceService();
185 } else if (AgentBase.class.isAssignableFrom(cdmType)){
186 return (IService<T>) repo.getAgentService();
187 } else if (Collection.class.isAssignableFrom(cdmType)){
188 return (IService<T>) repo.getCollectionService();
189 } else if (Collection.class.isAssignableFrom(cdmType)){
190 return (IService<T>) repo.getCollectionService();
191 } else {
192 throw new RuntimeException("Implementation to find service for " + cdmType + " still missing.");
193 }
194 }
195
196 }