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.update.schema.program.staticsource;
22  
23  import java.io.ByteArrayInputStream;
24  import java.io.UnsupportedEncodingException;
25  import java.util.ArrayList;
26  import java.util.HashMap;
27  import java.util.List;
28  import java.util.Map;
29  
30  import org.efaps.ci.CIAdminProgram;
31  import org.efaps.ci.CIType;
32  import org.efaps.db.Checkin;
33  import org.efaps.db.Insert;
34  import org.efaps.db.Instance;
35  import org.efaps.db.MultiPrintQuery;
36  import org.efaps.db.QueryBuilder;
37  import org.efaps.db.Update;
38  import org.efaps.update.schema.program.jasperreport.JasperReportCompiler;
39  import org.efaps.update.schema.program.staticsource.AbstractStaticSourceCompiler.AbstractSource;
40  import org.efaps.util.EFapsException;
41  import org.slf4j.Logger;
42  import org.slf4j.LoggerFactory;
43  
44  /**
45   * Class used to compile JavaScript and style sheets.
46   *
47   * @author The eFaps Team
48   * @version $Id$
49   * @param <T> sourcetype
50   */
51  public abstract class AbstractStaticSourceCompiler<T extends AbstractSource>
52  {
53  
54      /**
55       * Logging instance used in this class.
56       */
57      protected static final Logger LOG = LoggerFactory.getLogger(AbstractStaticSourceCompiler.class);
58  
59      /**
60       * Static Method that executes the method compile for the SubClasses
61       * CSSCompiler and JavaScriptCompiler.
62       * @param _classPathElements elements on the classpath
63       * @throws EFapsException on error
64       */
65      public static void compileAll(final List<String> _classPathElements)
66          throws EFapsException
67      {
68          new JasperReportCompiler(_classPathElements).compile();
69          new CSSCompiler().compile();
70          new JavaScriptCompiler().compile();
71          new WikiCompiler().compile();
72      }
73  
74      /**
75       * This method is doing the actual compiling in the following steps. <li>
76       * read all existing compiled source from the eFaps-DataBase</li> <li>read
77       * all sources from the eFaps-DataBase</li> <li>compile all sources
78       * (including the extending of any super type) and insert it into the
79       * eFaps-DataBase</li>
80       *
81       * @throws EFapsException on error
82       */
83      public void compile() throws EFapsException
84      {
85          final Map<String, String> compiled = readCompiledSources();
86  
87          final List<T> allsource = readSources();
88  
89          for (final T onesource : allsource) {
90  
91              if (AbstractStaticSourceCompiler.LOG.isInfoEnabled()) {
92                  AbstractStaticSourceCompiler.LOG.info("compiling " + onesource.getName());
93              }
94  
95              final List<Instance> supers = getSuper(onesource.getInstance());
96              final StringBuilder builder = new StringBuilder();
97              while (!supers.isEmpty()) {
98                  builder.append(getCompiledString(supers.get(supers.size() - 1)));
99                  supers.remove(supers.size() - 1);
100             }
101             builder.append(getCompiledString(onesource.getInstance()));
102             final Update update;
103             if (compiled.containsKey(onesource.getName())) {
104                 update = new Update(compiled.get(onesource.getName()));
105             } else {
106                 update = new Insert(getClassName4TypeCompiled());
107             }
108             update.add("Name", onesource.getName());
109             update.add("ProgramLink", "" + onesource.getInstance().getId());
110             update.executeWithoutAccessCheck();
111             final Instance instance = update.getInstance();
112             update.close();
113 
114             byte[] mybytes = null;
115             try {
116                 mybytes = builder.toString().getBytes("UTF-8");
117             } catch (final UnsupportedEncodingException e) {
118                 AbstractStaticSourceCompiler.LOG.error("error in reading Bytes from String using UTF-8", e);
119             }
120             final ByteArrayInputStream str = new ByteArrayInputStream(mybytes);
121             String name = onesource.getName().substring(0, onesource.getName().lastIndexOf("."));
122             name = name.substring(name.lastIndexOf(".") + 1)
123                             + onesource.getName().substring(onesource.getName().lastIndexOf("."));
124 
125             final Checkin checkin = new Checkin(instance);
126             checkin.executeWithoutAccessCheck(name, str, mybytes.length);
127         }
128 
129     }
130 
131     /**
132      * Get the UUID for the CompiledType.
133      *
134      * @return UUID for the CompiledType
135      */
136     protected abstract CIType getClassName4TypeCompiled();
137 
138     /**
139      * Get the UUID for the Type.
140      *
141      * @return UUID for the Type
142      */
143     protected abstract CIType getClassName4Type();
144 
145     /**
146      * Get the UUID for the Type2Type.
147      *
148      * @return UUID for the Type2Type
149      */
150     protected abstract CIType getClassName4Type2Type();
151 
152     /**
153      * Get a new AbstractSource to instantiate.
154      *
155      * @see #AbstractSource
156      * @see #readSources()
157      * @param _name     name of the source
158      * @param _instance Instance of the source
159      * @return AbstractSource
160      */
161     protected abstract T getNewSource(final String _name,
162                                       final Instance _instance);
163 
164     /**
165      * Get the compiled String for the Instance with OID _oid.
166      *
167      * @param _instance the instance the compiled String will be returned
168      * @return a compiled String of the Instance
169      * @throws EFapsException on error
170      */
171     protected abstract String getCompiledString(final Instance _instance)
172         throws EFapsException;
173 
174     /**
175      * This method reads all compiled Sources from the eFaps-DataBase and
176      * returns a map with name to oid relation.
177      *
178      * @return Map with name to oid of the compiled source
179      * @throws EFapsException on error
180      */
181     protected Map<String, String> readCompiledSources()
182         throws EFapsException
183     {
184         final Map<String, String> ret = new HashMap<String, String>();
185         final QueryBuilder queryBldr = new QueryBuilder(getClassName4TypeCompiled());
186         final MultiPrintQuery multi = queryBldr.getPrint();
187         multi.addAttribute(CIAdminProgram.StaticCompiled.Name);
188         multi.executeWithoutAccessCheck();
189         while (multi.next()) {
190             final String name = multi.<String>getAttribute(CIAdminProgram.StaticCompiled.Name);
191             ret.put(name, multi.getCurrentInstance().getOid());
192         }
193         return ret;
194     }
195 
196     /**
197      * This method reads all Sources from the eFapsDataBase and returns for each
198      * Source a Instance of AbstractSource in a List.
199      *
200      * @return List with AbstractSources
201      * @throws EFapsException on error
202      */
203     protected List<T> readSources()
204         throws EFapsException
205     {
206         final List<T> ret = new ArrayList<>();
207         final QueryBuilder queryBldr = new QueryBuilder(getClassName4Type());
208         final MultiPrintQuery multi = queryBldr.getPrint();
209         multi.addAttribute(CIAdminProgram.Abstract.Name);
210         multi.executeWithoutAccessCheck();
211         while (multi.next()) {
212             final String name = multi.<String>getAttribute(CIAdminProgram.StaticCompiled.Name);
213             ret.add(getNewSource(name, multi.getCurrentInstance()));
214         }
215         return ret;
216     }
217 
218     /**
219      * Recursive method that searches the SuperSource for the current Instance
220      * identified by the oid.
221      *
222      * @param _instance Instance the Super Instance will be searched
223      * @return List of SuperSources in reverse order
224      * @throws EFapsException error
225      */
226     protected List<Instance> getSuper(final Instance _instance)
227         throws EFapsException
228     {
229         final List<Instance> ret = new ArrayList<Instance>();
230         final QueryBuilder queryBldr = new QueryBuilder(getClassName4Type2Type());
231         queryBldr.addWhereAttrEqValue(CIAdminProgram.Program2Program.From, _instance.getId());
232         final MultiPrintQuery multi = queryBldr.getPrint();
233         multi.addAttribute(CIAdminProgram.Program2Program.To);
234         multi.execute();
235         if (multi.next()) {
236             final Instance instance = Instance.get(getClassName4Type().getType(),
237                                              multi.<Long>getAttribute(CIAdminProgram.Program2Program.To));
238             ret.add(instance);
239             ret.addAll(getSuper(instance));
240         }
241         return ret;
242     }
243 
244     /**
245      * Class to access one source.
246      */
247     public static abstract class AbstractSource
248     {
249         /**
250          * Stores the name of this source.
251          */
252         private final String name;
253 
254         /**
255          * Instance of this source.
256          */
257         private final Instance instance;
258 
259         /**
260          * Constructor setting all instance variables.
261          *
262          * @param _name     name of the source
263          * @param _instance Instance of the source
264          */
265         public AbstractSource(final String _name,
266                               final Instance _instance)
267         {
268             this.name = _name;
269             this.instance = _instance;
270         }
271 
272         /**
273          * This is the getter method for the instance variable {@link #name}.
274          *
275          * @return value of instance variable {@link #name}
276          */
277         public String getName()
278         {
279             return this.name;
280         }
281 
282         /**
283          * This is the getter method for the instance variable {@link #instance}.
284          *
285          * @return value of instance variable {@link #instance}
286          */
287         public Instance getInstance()
288         {
289             return this.instance;
290         }
291     }
292 }