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 import java.io.InputStream;
23 import java.io.OutputStream;
24
25 import org.efaps.admin.access.AccessTypeEnums;
26 import org.efaps.admin.event.EventType;
27 import org.efaps.db.store.Resource;
28 import org.efaps.util.EFapsException;
29 import org.slf4j.Logger;
30 import org.slf4j.LoggerFactory;
31
32 /**
33 * The class is used to checkout a file from a given attribute of an object.
34 *
35 * @author The eFaps Team
36 * @version $Id$
37 */
38 public class Checkout
39 extends AbstractAction
40 {
41 /**
42 * Logging instance used in this class.
43 */
44 private static final Logger LOG = LoggerFactory.getLogger(Checkout.class);
45
46 /**
47 * Stores the file name after pre processing.
48 *
49 * @see #preprocess
50 * @see #getFileName()
51 */
52 private String fileName = null;
53
54 /**
55 * Length of the file in bytes.
56 */
57 private long fileLength;
58
59 /**
60 * Constructor with object id as string.
61 *
62 * @param _oid oid of object on which the checkout is made
63 */
64 public Checkout(final String _oid)
65 {
66 this(Instance.get(_oid));
67 }
68
69 /**
70 * Constructor with instance object.
71 *
72 * @param _instance instance on which the checkout is made
73 */
74 public Checkout(final Instance _instance)
75 {
76 super.setInstance(_instance);
77 }
78
79 /**
80 * The method is only a dummy method and closes the checkout action. The
81 * method should be called, if in the future the checkout class needs a
82 * call to this method.
83 */
84 public void close()
85 {
86 }
87
88 /**
89 * Executes the checkout with an output stream.
90 *
91 * @param _out output stream where to write the file
92 * @throws EFapsException if the current context user has now access to
93 * checkout the file out of the eFaps object
94 */
95 public void execute(final OutputStream _out)
96 throws EFapsException
97 {
98 final boolean hasAccess = super.getInstance().getType().hasAccess(super.getInstance(),
99 AccessTypeEnums.CHECKOUT.getAccessType());
100 if (!hasAccess) {
101 throw new EFapsException(this.getClass(), "execute.NoAccess");
102 }
103 this.executeWithoutAccessCheck(_out);
104 }
105
106 /**
107 * Executes the checkout for output streams without checking the access
108 * rights (but with triggers).
109 * <ol>
110 * <li>executes the pre checkout trigger (if exists)</li>
111 * <li>executes the checkout trigger (if exists)</li>
112 * <li>executes if no checkout trigger exists or the checkout trigger is
113 * not executed the update ({@see #executeWithoutTrigger})</li>
114 * <li>executes the post checkout trigger (if exists)</li>
115 * </ol>
116 *
117 * @param _out output stream where to write the file
118 * @throws EFapsException if checkout action fails
119 */
120 public void executeWithoutAccessCheck(final OutputStream _out)
121 throws EFapsException
122 {
123 executeEvents(EventType.CHECKOUT_PRE);
124 if (!executeEvents(EventType.CHECKOUT_OVERRIDE)) {
125 this.executeWithoutTrigger(_out);
126 }
127 executeEvents(EventType.CHECKOUT_POST);
128 }
129
130 /**
131 * Executes the checkout for output streams without checking the access
132 * rights and without triggers.
133 *
134 * @param _out output stream where to write the file
135 * @throws EFapsException if checkout action fails
136 */
137 public void executeWithoutTrigger(final OutputStream _out)
138 throws EFapsException
139 {
140 Resource storeRsrc = null;
141 try {
142 storeRsrc = Context.getThreadContext().getStoreResource(getInstance(), Resource.StoreEvent.READ);
143 storeRsrc.read(_out);
144 this.fileLength = storeRsrc.getFileLength();
145 this.fileName = storeRsrc.getFileName();
146 storeRsrc.commit();
147 } catch (final EFapsException e) {
148 Checkout.LOG.error("could not checkout " + super.getInstance(), e);
149 throw e;
150 } finally {
151 if ((storeRsrc != null) && storeRsrc.isOpened()) {
152 storeRsrc.abort();
153 }
154 }
155 }
156
157 /**
158 * Executes the checkout and returns an input stream by calling method
159 * {@link #executeWithoutAccessCheck()}.
160 *
161 * @return input stream of the checked in file
162 * @throws EFapsException if the current context user has now access to
163 * checkout the file out of the eFaps object
164 * @see #executeWithoutAccessCheck()
165 */
166 public InputStream execute()
167 throws EFapsException
168 {
169 final boolean hasAccess = super.getInstance().getType().hasAccess(super.getInstance(),
170 AccessTypeEnums.CHECKOUT.getAccessType());
171 if (!hasAccess) {
172 throw new EFapsException(this.getClass(), "execute.NoAccess");
173 }
174 return this.executeWithoutAccessCheck();
175 }
176
177 /**
178 * Executes the checkout without an access check (but with triggers) and
179 * returns an input streams of the checked in file. The returned input
180 * stream must be closed, because the returned inputs stream also commit
181 * the store resource. Otherwise the transaction is rolled back!
182 * <ol>
183 * <li>executes the pre checkout trigger (if exists)</li>
184 * <li>executes the checkout trigger (if exists)</li>
185 * <li>executes if no checkout trigger exists or the checkout trigger is
186 * not executed the update ({@see #executeWithoutTrigger})</li>
187 * <li>executes the post checkout trigger (if exists)</li>
188 * </ol>
189 *
190 * @throws EFapsException if checkout action fails
191 * @return input stream containing the file
192 */
193 public InputStream executeWithoutAccessCheck()
194 throws EFapsException
195 {
196 InputStream ret = null;
197 executeEvents(EventType.CHECKOUT_PRE);
198 if (!executeEvents(EventType.CHECKOUT_OVERRIDE)) {
199 ret = this.executeWithoutTrigger();
200 }
201 executeEvents(EventType.CHECKOUT_POST);
202 return ret;
203 }
204
205 /**
206 * Executes the checkout without an access check and without triggers and
207 * returns an input streams of the checked in file. The returned input
208 * stream must be closed, because the returned inputs stream also commit
209 * the store resource. Otherwise the transaction is rolled back!
210 *
211 * @throws EFapsException if checkout action fails
212 * @return input stream containing the file
213 */
214 public InputStream executeWithoutTrigger()
215 throws EFapsException
216 {
217 Resource storeRsrc = null;
218 InputStream in = null;
219 try {
220 storeRsrc = Context.getThreadContext().getStoreResource(getInstance(), Resource.StoreEvent.READ);
221 in = storeRsrc.read();
222 this.fileLength = storeRsrc.getFileLength();
223 this.fileName = storeRsrc.getFileName();
224 storeRsrc.commit();
225 } catch (final EFapsException e) {
226 Checkout.LOG.error("could not checkout " + super.getInstance(), e);
227 throw e;
228 } finally {
229 if ((in == null) && (storeRsrc != null) && storeRsrc.isOpened()) {
230 storeRsrc.abort();
231 }
232 }
233 return in;
234 }
235
236 /**
237 * This is the getter method for instance variable {@link #fileName}.
238 *
239 * @return the fileName of the instance variable {@link #fileName}.
240 * @see #fileName
241 */
242 public String getFileName()
243 {
244 return this.fileName;
245 }
246
247 /**
248 * This is the getter method for instance variable {@link #fileLength}.
249 *
250 * @return the fileName of the instance variable {@link #fileLength}.
251 * @see #fileLength
252 */
253 public long getFileLength()
254 {
255 return this.fileLength;
256 }
257 }