1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 package com.sun.star.report.pentaho;
24 
25 import com.sun.star.beans.NamedValue;
26 import com.sun.star.beans.PropertyVetoException;
27 import com.sun.star.beans.UnknownPropertyException;
28 import com.sun.star.beans.XPropertyChangeListener;
29 import com.sun.star.beans.XPropertySet;
30 import com.sun.star.beans.XVetoableChangeListener;
31 import com.sun.star.container.XChild;
32 import com.sun.star.embed.XStorage;
33 import com.sun.star.frame.XModel;
34 import com.sun.star.lang.IllegalArgumentException;
35 import com.sun.star.lang.WrappedTargetException;
36 import com.sun.star.lang.XInitialization;
37 import com.sun.star.lang.XServiceInfo;
38 import com.sun.star.lang.XSingleComponentFactory;
39 import com.sun.star.lib.uno.helper.Factory;
40 import com.sun.star.lib.uno.helper.PropertySetMixin;
41 import com.sun.star.lib.uno.helper.WeakBase;
42 import com.sun.star.registry.InvalidRegistryException;
43 import com.sun.star.registry.InvalidValueException;
44 import com.sun.star.registry.XRegistryKey;
45 import com.sun.star.registry.XSimpleRegistry;
46 import com.sun.star.report.DataSourceFactory;
47 import com.sun.star.report.JobProperties;
48 import com.sun.star.report.ReportEngineParameterNames;
49 import com.sun.star.report.ReportExecutionException;
50 import com.sun.star.report.ReportJob;
51 import com.sun.star.report.ReportJobDefinition;
52 import com.sun.star.report.ReportJobFactory;
53 import com.sun.star.report.SDBCReportDataFactory;
54 import com.sun.star.report.SOImageService;
55 import com.sun.star.report.StorageRepository;
56 import com.sun.star.report.XReportDefinition;
57 import com.sun.star.sdb.XDocumentDataSource;
58 import com.sun.star.sdbc.XConnection;
59 import com.sun.star.sdbc.XRowSet;
60 import com.sun.star.task.XJob;
61 import com.sun.star.uno.Exception;
62 import com.sun.star.uno.Type;
63 import com.sun.star.uno.UnoRuntime;
64 import com.sun.star.uno.XComponentContext;
65 
66 import java.util.logging.Level;
67 import java.util.logging.Logger;
68 
69 import org.apache.commons.logging.Log;
70 import org.apache.commons.logging.LogFactory;
71 
72 /**
73  * This class capsulates the class, that implements the minimal component, a factory for creating the service
74  * (<CODE>__getComponentFactory</CODE>) and a method, that writes the information into the given registry key
75  * (<CODE>__writeRegistryServiceInfo</CODE>).
76  */
77 public class SOReportJobFactory
78 {
79 
SOReportJobFactory()80     private SOReportJobFactory()
81     {
82     }
83 
84     public static class _SOReportJobFactory extends WeakBase implements XInitialization, XServiceInfo, XJob, XPropertySet, ReportJobFactory
85     {
86 
87         private static final Log LOGGER = LogFactory.getLog(_SOReportJobFactory.class);
88         /**
89          * The service name, that must be used to get an instance of this service.
90          */
91         private static final String __serviceName =
92                 "com.sun.star.report.pentaho.SOReportJobFactory";
93         private final PropertySetMixin m_prophlp;
94         /**
95          * The initial component contextr, that gives access to the service manager, supported singletons, ... It's
96          * often later used
97          */
98         private final XComponentContext m_cmpCtx;
99         private XConnection activeConnection;
100         private XReportDefinition report;
101 
_SOReportJobFactory(final XComponentContext xCompContext)102         public _SOReportJobFactory(final XComponentContext xCompContext)
103         {
104             m_cmpCtx = xCompContext;
105             m_prophlp = new PropertySetMixin(m_cmpCtx, this,
106                     new Type(XJob.class),
107                     null); // no optionals
108         }
109 
110         /**
111          * This method is a member of the interface for initializing an object directly after its creation.
112          *
113          * @param object This array of arbitrary objects will be passed to the component after its creation.
114          * @throws Exception Every exception will not be handled, but will be passed to the caller.
115          */
initialize(final Object[] object)116         public void initialize(final Object[] object)
117                 throws com.sun.star.uno.Exception
118         {
119             /* The component describes what arguments its expected and in which
120              * order!At this point you can read the objects and can intialize
121              * your component using these objects.
122              */
123         }
124 
125         /**
126          * This method returns an array of all supported service names.
127          *
128          * @return Array of supported service names.
129          */
getSupportedServiceNames()130         public String[] getSupportedServiceNames()
131         {
132             return getServiceNames();
133         }
134 
135         /**
136          * This method is a simple helper function to used in the static component initialisation functions as well as
137          * in getSupportedServiceNames.
138          * @return
139          */
getServiceNames()140         public static String[] getServiceNames()
141         {
142             return new String[]
143                     {
144                         __serviceName
145                     };
146         }
147 
148         /**
149          * This method returns true, if the given service will be supported by the component.
150          *
151          * @param sServiceName Service name.
152          * @return True, if the given service name will be supported.
153          */
supportsService(final String sServiceName)154         public boolean supportsService(final String sServiceName)
155         {
156             return sServiceName.equals(__serviceName);
157         }
158 
159         /**
160          * Return the class name of the component.
161          *
162          * @return Class name of the component.
163          */
getImplementationName()164         public String getImplementationName()
165         {
166             return SOReportJobFactory.class.getName();
167         }
168 
getLocaleFromRegistry(final XSimpleRegistry simpleReg, final String path, final String value)169         private String getLocaleFromRegistry(final XSimpleRegistry simpleReg, final String path, final String value)
170         {
171             String currentLocale = null;
172             try
173             {
174                 simpleReg.open(path, true, false);
175                 final XRegistryKey xRegistryRootKey = simpleReg.getRootKey();
176                 // read locale
177                 final XRegistryKey locale = xRegistryRootKey.openKey(value);
178                 if (locale != null)
179                 {
180                     final String newLocale = locale.getStringValue();
181                     if (newLocale != null)
182                     {
183                         currentLocale = newLocale.replace('-', '_');
184                     }
185                 }
186             }
187             catch (InvalidValueException ex)
188             {
189                 Logger.getLogger(SOReportJobFactory.class.getName()).log(Level.SEVERE, null, ex);
190             }
191             catch (InvalidRegistryException ex)
192             {
193                 Logger.getLogger(SOReportJobFactory.class.getName()).log(Level.SEVERE, null, ex);
194             }
195 
196             return currentLocale;
197         }
198 
execute(final NamedValue[] namedValue)199         public Object execute(final NamedValue[] namedValue)
200                 throws com.sun.star.lang.IllegalArgumentException, com.sun.star.uno.Exception
201         {
202             final ClassLoader cl = java.lang.Thread.currentThread().getContextClassLoader();
203             Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
204             try
205             {
206                 final XSimpleRegistry simpleReg = (XSimpleRegistry) UnoRuntime.queryInterface(XSimpleRegistry.class,
207                         m_cmpCtx.getServiceManager().createInstanceWithContext("com.sun.star.configuration.ConfigurationRegistry", m_cmpCtx));
208 
209                 String currentLocale = getLocaleFromRegistry(simpleReg, "org.openoffice.Setup", "L10N/ooSetupSystemLocale");
210                 if (currentLocale == null || "".equals(currentLocale))
211                 {
212                     currentLocale = getLocaleFromRegistry(simpleReg, "org.openoffice.Office.Linguistic", "General/DefaultLocale");
213                 }
214                 if (currentLocale != null && !"".equals(currentLocale))
215                 {
216                     System.setProperty("org.pentaho.reporting.libraries.formula.locale", currentLocale);
217                 }
218                 final ReportJob job = createReportJob(namedValue);
219                 job.execute();
220 
221             }
222             catch (java.lang.Exception e)
223             {
224                 LOGGER.error("ReportProcessing failed", e);
225                 throw new com.sun.star.lang.WrappedTargetException(e.getMessage(), this, null);
226             }
227             catch (java.lang.IncompatibleClassChangeError e2)
228             {
229                 LOGGER.error("Detected an IncompatibleClassChangeError");
230                 throw new com.sun.star.lang.WrappedTargetException("caught a " + e2.getClass().getName(), this, new com.sun.star.uno.Exception(e2.getLocalizedMessage()));
231             }
232             Thread.currentThread().setContextClassLoader(cl);
233 
234             return null;
235         }
236 
createReportJob(final NamedValue[] namedValue)237         public ReportJob createReportJob(final NamedValue[] namedValue) throws IllegalArgumentException, ReportExecutionException, Exception
238         {
239             XStorage input = null;
240             XStorage output = null;
241             XRowSet rowSet = null;
242             String mimetype = null;
243             String author = null;
244             String title = null;
245             Integer maxRows = null;
246 
247             for (int i = 0; i < namedValue.length; ++i)
248             {
249                 final NamedValue aProps = namedValue[i];
250                 if ("ActiveConnection".equalsIgnoreCase(aProps.Name))
251                 {
252                     activeConnection = (XConnection) UnoRuntime.queryInterface(XConnection.class, aProps.Value);
253                 }
254                 else if ("ReportDefinition".equalsIgnoreCase(aProps.Name))
255                 {
256                     report = (XReportDefinition) UnoRuntime.queryInterface(XReportDefinition.class, aProps.Value);
257                 }
258                 else if ("InputStorage".equalsIgnoreCase(aProps.Name))
259                 {
260                     input = (XStorage) UnoRuntime.queryInterface(XStorage.class, aProps.Value);
261                 }
262                 else if ("OutputStorage".equalsIgnoreCase(aProps.Name))
263                 {
264                     output = (XStorage) UnoRuntime.queryInterface(XStorage.class, aProps.Value);
265                 }
266                 else if ("RowSet".equalsIgnoreCase(aProps.Name))
267                 {
268                     rowSet = (XRowSet) UnoRuntime.queryInterface(XRowSet.class, aProps.Value);
269                 }
270                 else if ("mimetype".equalsIgnoreCase(aProps.Name))
271                 {
272                     mimetype = (String) aProps.Value;
273                 }
274                 else if ("MaxRows".equalsIgnoreCase(aProps.Name))
275                 {
276                     maxRows = (Integer) aProps.Value;
277                 }
278                 else if (ReportEngineParameterNames.AUTHOR.equalsIgnoreCase(aProps.Name))
279                 {
280                     author = (String) aProps.Value;
281                 }
282                 else if (ReportEngineParameterNames.TITLE.equalsIgnoreCase(aProps.Name))
283                 {
284                     title = (String) aProps.Value;
285                 }
286             }
287 
288             if (input == null || output == null)
289             {
290                 throw new com.sun.star.lang.IllegalArgumentException();
291             }
292 
293             if (rowSet == null)
294             {
295                 if (report == null || activeConnection == null)
296                 {
297                     throw new com.sun.star.lang.IllegalArgumentException();
298                 }
299                 mimetype = report.getMimeType();
300             }
301             else
302             {
303                 final XPropertySet set = (XPropertySet) UnoRuntime.queryInterface(XPropertySet.class, rowSet);
304                 if (set == null)
305                 {
306                     throw new com.sun.star.lang.IllegalArgumentException();
307                 }
308                 activeConnection = (XConnection) UnoRuntime.queryInterface(XConnection.class, set.getPropertyValue("ActiveConnection"));
309             }
310             if (mimetype == null)
311             {
312                 mimetype = PentahoReportEngineMetaData.OPENDOCUMENT_TEXT;
313             }
314 
315             final XChild child = UnoRuntime.queryInterface(XChild.class, activeConnection);
316             final XDocumentDataSource docSource = UnoRuntime.queryInterface(XDocumentDataSource.class, child.getParent());
317             final XModel model = UnoRuntime.queryInterface(XModel.class, docSource.getDatabaseDocument());
318             final DataSourceFactory dataFactory = new SDBCReportDataFactory(m_cmpCtx, activeConnection);
319             final StorageRepository storageRepository = new StorageRepository(input, output, model.getURL());
320 
321             final String inputName = "content.xml";
322             final String outputName = "content.xml";
323 
324             final PentahoReportEngine engine = new PentahoReportEngine();
325             final ReportJobDefinition definition = engine.createJobDefinition();
326             final JobProperties procParms = definition.getProcessingParameters();
327             procParms.setProperty(ReportEngineParameterNames.INPUT_REPOSITORY, storageRepository);
328             procParms.setProperty(ReportEngineParameterNames.OUTPUT_REPOSITORY, storageRepository);
329             procParms.setProperty(ReportEngineParameterNames.INPUT_NAME, inputName);
330             procParms.setProperty(ReportEngineParameterNames.OUTPUT_NAME, outputName);
331             procParms.setProperty(ReportEngineParameterNames.CONTENT_TYPE, mimetype);
332             procParms.setProperty(ReportEngineParameterNames.INPUT_DATASOURCE_FACTORY, dataFactory);
333             procParms.setProperty(ReportEngineParameterNames.IMAGE_SERVICE, new SOImageService(m_cmpCtx));
334             procParms.setProperty(ReportEngineParameterNames.INPUT_REPORTJOB_FACTORY, this);
335             procParms.setProperty(ReportEngineParameterNames.MAXROWS, maxRows);
336             if (author != null)
337             {
338                 procParms.setProperty(ReportEngineParameterNames.AUTHOR, author);
339             }
340             if (title != null)
341             {
342                 procParms.setProperty(ReportEngineParameterNames.TITLE, title);
343             }
344 
345             return engine.createJob(definition);
346         }
347 
348         // com.sun.star.beans.XPropertySet:
getPropertySetInfo()349         public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
350         {
351             return m_prophlp.getPropertySetInfo();
352         }
353 
setPropertyValue(final String aPropertyName, final Object aValue)354         public void setPropertyValue(final String aPropertyName, final Object aValue)
355                 throws UnknownPropertyException, PropertyVetoException, com.sun.star.lang.IllegalArgumentException,
356                 WrappedTargetException
357         {
358             m_prophlp.setPropertyValue(aPropertyName, aValue);
359         }
360 
getPropertyValue(final String aPropertyName)361         public Object getPropertyValue(final String aPropertyName)
362                 throws UnknownPropertyException, WrappedTargetException
363         {
364             return m_prophlp.getPropertyValue(aPropertyName);
365         }
366 
addPropertyChangeListener(final String aPropertyName, final XPropertyChangeListener xListener)367         public void addPropertyChangeListener(final String aPropertyName, final XPropertyChangeListener xListener)
368                 throws UnknownPropertyException, WrappedTargetException
369         {
370             m_prophlp.addPropertyChangeListener(aPropertyName, xListener);
371         }
372 
removePropertyChangeListener(final String aPropertyName, final XPropertyChangeListener xListener)373         public void removePropertyChangeListener(final String aPropertyName, final XPropertyChangeListener xListener)
374                 throws UnknownPropertyException, WrappedTargetException
375         {
376             m_prophlp.removePropertyChangeListener(aPropertyName, xListener);
377         }
378 
addVetoableChangeListener(final String aPropertyName, final XVetoableChangeListener xListener)379         public void addVetoableChangeListener(final String aPropertyName, final XVetoableChangeListener xListener)
380                 throws UnknownPropertyException, WrappedTargetException
381         {
382             m_prophlp.addVetoableChangeListener(aPropertyName, xListener);
383         }
384 
removeVetoableChangeListener(final String aPropertyName, final XVetoableChangeListener xListener)385         public void removeVetoableChangeListener(final String aPropertyName, final XVetoableChangeListener xListener)
386                 throws UnknownPropertyException, WrappedTargetException
387         {
388             m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);
389         }
390     }
391 
392     /**
393      * Gives a factory for creating the service. This method is called by the <code>JavaLoader</code>
394      * <p/>
395      *
396      * @param sImplName the name of the implementation for which a service is desired
397      * @return returns a <code>XSingleComponentFactory</code> for creating the component
398      * @see com.sun.star.comp.loader.JavaLoader
399      */
__getComponentFactory(final String sImplName)400     public static XSingleComponentFactory __getComponentFactory(final String sImplName)
401     {
402         XSingleComponentFactory xFactory = null;
403 
404         try
405         {
406             if (sImplName.equals(_SOReportJobFactory.class.getName()))
407             {
408                 xFactory = Factory.createComponentFactory(_SOReportJobFactory.class, _SOReportJobFactory.getServiceNames());
409             }
410             else if (sImplName.equals(SOFunctionManager.class.getName()))
411             {
412                 xFactory = Factory.createComponentFactory(SOFunctionManager.class, SOFunctionManager.getServiceNames());
413             }
414             else if (sImplName.equals(SOFormulaParser.class.getName()))
415             {
416                 xFactory = Factory.createComponentFactory(SOFormulaParser.class, SOFormulaParser.getServiceNames());
417             }
418         }
419         catch (java.lang.IncompatibleClassChangeError e2)
420         {
421         }
422 
423         return xFactory;
424     }
425 
426     /**
427      * Writes the service information into the given registry key. This method is called by the <code>JavaLoader</code>
428      * <p/>
429      *
430      * @param regKey the registryKey
431      * @return returns true if the operation succeeded
432      * @see com.sun.star.comp.loader.JavaLoader
433      */
__writeRegistryServiceInfo(final XRegistryKey regKey)434     public static boolean __writeRegistryServiceInfo(final XRegistryKey regKey)
435     {
436         return Factory.writeRegistryServiceInfo(SOFunctionManager.class.getName(),
437                 SOFunctionManager.getServiceNames(),
438                 regKey) && Factory.writeRegistryServiceInfo(_SOReportJobFactory.class.getName(),
439                 _SOReportJobFactory.getServiceNames(),
440                 regKey) && Factory.writeRegistryServiceInfo(SOFormulaParser.class.getName(),
441                 SOFormulaParser.getServiceNames(),
442                 regKey);
443     }
444 }
445