1 /*
2 * Copyright 2003 - 2013 The eFaps Team
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 * Revision: $Rev$
17 * Last Changed: $Date$
18 * Last Changed By: $Author$
19 */
20
21 package org.efaps.db;
22
23 import java.sql.SQLException;
24 import java.util.ArrayList;
25 import java.util.List;
26
27 import org.efaps.admin.access.AccessCache;
28 import org.efaps.admin.access.AccessTypeEnums;
29 import org.efaps.admin.datamodel.SQLTable;
30 import org.efaps.admin.datamodel.Type;
31 import org.efaps.admin.event.EventDefinition;
32 import org.efaps.admin.event.EventType;
33 import org.efaps.admin.event.Parameter;
34 import org.efaps.admin.event.Parameter.ParameterValues;
35 import org.efaps.db.store.Resource;
36 import org.efaps.db.transaction.ConnectionResource;
37 import org.efaps.db.wrapper.SQLDelete;
38 import org.efaps.db.wrapper.SQLDelete.DeleteDefintion;
39 import org.efaps.util.EFapsException;
40
41 /**
42 * The class is used as interface to the eFaps kernel to delete one object.
43 *
44 * @author The eFaps Team
45 * @version $Id$
46 */
47 public class Delete
48 {
49 /**
50 * The instance variable stores the instance for which this update is made.
51 *
52 * @see #getInstance()
53 */
54 private final Instance instance;
55
56 /**
57 * @param _instance Instance to be deleted
58 */
59 public Delete(final Instance _instance)
60 {
61 this.instance = _instance;
62 }
63
64 /**
65 * @param _type type of the Instance to be deleted
66 * @param _id id of the Instance to be deleted
67 */
68 public Delete(final Type _type,
69 final String _id)
70 {
71 this.instance = Instance.get(_type, _id);
72 }
73
74 /**
75 * @param _type type of the Instance to be deleted
76 * @param _id id of the Instance to be deleted
77 */
78 public Delete(final Type _type, final long _id)
79 {
80 this.instance = Instance.get(_type, _id);
81 }
82
83 /**
84 * @param _oid oid of the Instance to be deleted
85 */
86 public Delete(final String _oid)
87 {
88 this.instance = Instance.get(_oid);
89 }
90
91 /**
92 * First it is checked if the user has access to delete the eFaps object
93 * defined in {@link #instance}. If no access, an exception is thrown. If
94 * the context user has access. the delete is made with
95 * {@link #executeWithoutAccessCheck}.
96 *
97 * @throws EFapsException if the current context user has no delete access
98 * on given eFaps object.
99 * @see #executeWithoutAccessCheck()
100 */
101 public void execute()
102 throws EFapsException
103 {
104 AccessCache.registerUpdate(getInstance());
105 final boolean hasAccess = this.instance.getType().hasAccess(this.instance,
106 AccessTypeEnums.DELETE.getAccessType());
107 if (!hasAccess) {
108 throw new EFapsException(getClass(), "execute.NoAccess", this.instance);
109 }
110 executeWithoutAccessCheck();
111 }
112
113 /**
114 * Executes the delete without checking the access rights (but with
115 * triggers).
116 * <ol>
117 * <li>executes the pre delete trigger (if exists)</li>
118 * <li>executes the delete trigger (if exists)</li>
119 * <li>executes if no delete trigger exists or the delete trigger is not
120 * executed the update ({@see #executeWithoutTrigger})</li>
121 * <li>executes the post delete trigger (if exists)</li>
122 * </ol>
123 *
124 * @throws EFapsException thrown from {@link #executeWithoutTrigger} or
125 * when the status is invalid
126 * @see #executeWithoutTrigger()
127 */
128 public void executeWithoutAccessCheck()
129 throws EFapsException
130 {
131 executeEvents(EventType.DELETE_PRE);
132 if (!executeEvents(EventType.DELETE_OVERRIDE)) {
133 executeWithoutTrigger();
134 }
135 executeEvents(EventType.DELETE_POST);
136 }
137
138 /**
139 * <p>The executes is done without calling triggers and check of access
140 * rights. The method executes the delete. For the object, a delete is made
141 * in all SQL tables from the type (if the SQL table is not read only!). If
142 * a store is defined for the type, the checked in file is also deleted
143 * (with the help of the store resource implementation; if the store
144 * resource implementation has not implemented the delete, the file is not
145 * deleted!).</p>
146 * <p>It is not checked if the current context user has access to delete
147 * the eFaps object defined in {@link #instance}.</p>
148 *
149 * @see SQLTable#isReadOnly()
150 * @throws EFapsException on error
151 */
152 public void executeWithoutTrigger()
153 throws EFapsException
154 {
155 final Context context = Context.getThreadContext();
156 ConnectionResource con = null;
157 try {
158 con = context.getConnectionResource();
159 // first remove the storeresource, because the information needed from the general
160 // instance to actually delete will be removed in the second step
161 Resource storeRsrc = null;
162 try {
163 if (getInstance().getType().hasStore()) {
164 storeRsrc = context.getStoreResource(getInstance(), Resource.StoreEvent.DELETE);
165 storeRsrc.delete();
166 storeRsrc.commit();
167 }
168 } finally {
169 if ((storeRsrc != null) && storeRsrc.isOpened()) {
170 storeRsrc.abort();
171 }
172 }
173 try {
174 final List<DeleteDefintion> defs = new ArrayList<DeleteDefintion>();
175 defs.addAll(GeneralInstance.getDeleteDefintion(getInstance(), con.getConnection()));
176 final SQLTable mainTable = getInstance().getType().getMainTable();
177 for (final SQLTable curTable : getInstance().getType().getTables()) {
178 if ((curTable != mainTable) && !curTable.isReadOnly()) {
179 defs.add(new DeleteDefintion(curTable.getSqlTable(),
180 curTable.getSqlColId(), getInstance().getId()));
181 }
182 }
183 defs.add(new DeleteDefintion(mainTable.getSqlTable(), mainTable.getSqlColId(), getInstance().getId()));
184 final SQLDelete delete = Context.getDbType().newDelete(defs.toArray(new DeleteDefintion[defs.size()]));
185 delete.execute(con.getConnection());
186 } catch (final SQLException e) {
187 throw new EFapsException(getClass(),
188 "executeWithoutAccessCheck.SQLException", e, this.instance);
189 }
190 con.commit();
191 } finally {
192 if ((con != null) && con.isOpened()) {
193 con.abort();
194 }
195 }
196 }
197
198 /**
199 * This is the getter method for instance variable {@link #instance}.
200 *
201 * @return value of instance variable {@link #instance}
202 * @see #instance
203 */
204 public Instance getInstance()
205 {
206 return this.instance;
207 }
208
209 /**
210 * The method gets all events for the given EventType and executes them in
211 * the given order. If no events are defined, nothing is done. The method
212 * return <i>true</i> if a event was found, otherwise <i>false</i>.
213 *
214 * @param _eventtype event type to execute
215 * @return <i>true</i> if a trigger was found and executed, otherwise
216 * <i>false</i>
217 * @throws EFapsException on error
218 */
219 private boolean executeEvents(final EventType _eventtype)
220 throws EFapsException
221 {
222 final boolean ret;
223 final List<EventDefinition> triggers = getInstance().getType().getEvents(_eventtype);
224 if (triggers == null) {
225 ret = false;
226 } else {
227 final Parameter parameter = new Parameter();
228
229 parameter.put(ParameterValues.INSTANCE, getInstance());
230 for (final EventDefinition evenDef : triggers) {
231 evenDef.execute(parameter);
232 }
233 ret = true;
234 }
235 return ret;
236 }
237 }