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 }