LanguageTool: don't crash if REST protocol isn't set
[LibreOffice.git] / reportbuilder / java / org / libreoffice / report / pentaho / SOFormulaParser.java
blob24bf1a682d3e1d9558b3643397c046558bd0ac24
1 /*
2 * This file is part of the LibreOffice project.
4 * This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 * This file incorporates work covered by the following license notice:
10 * Licensed to the Apache Software Foundation (ASF) under one or more
11 * contributor license agreements. See the NOTICE file distributed
12 * with this work for additional information regarding copyright
13 * ownership. The ASF licenses this file to you under the Apache
14 * License, Version 2.0 (the "License"); you may not use this file
15 * except in compliance with the License. You may obtain a copy of
16 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
18 package org.libreoffice.report.pentaho;
21 import com.sun.star.lang.XServiceInfo;
22 import com.sun.star.lib.uno.helper.ComponentBase;
23 import com.sun.star.lib.uno.helper.PropertySetMixin;
24 import com.sun.star.sheet.FormulaLanguage;
25 import com.sun.star.sheet.FormulaMapGroup;
26 import com.sun.star.sheet.FormulaMapGroupSpecialOffset;
27 import com.sun.star.sheet.FormulaOpCodeMapEntry;
28 import com.sun.star.sheet.FormulaToken;
29 import com.sun.star.sheet.XFormulaOpCodeMapper;
30 import com.sun.star.uno.Any;
31 import com.sun.star.uno.Exception;
32 import com.sun.star.uno.Type;
33 import com.sun.star.uno.UnoRuntime;
34 import com.sun.star.uno.XComponentContext;
36 import java.io.StringReader;
38 import java.util.ArrayList;
39 import java.util.HashMap;
40 import java.util.Iterator;
41 import java.util.List;
42 import java.util.Map;
44 import org.pentaho.reporting.libraries.base.config.Configuration;
45 import org.pentaho.reporting.libraries.formula.DefaultFormulaContext;
46 import org.pentaho.reporting.libraries.formula.function.FunctionRegistry;
47 import org.pentaho.reporting.libraries.formula.parser.FormulaParser;
48 import org.pentaho.reporting.libraries.formula.parser.GeneratedFormulaParserConstants;
49 import org.pentaho.reporting.libraries.formula.parser.GeneratedFormulaParserTokenManager;
50 import org.pentaho.reporting.libraries.formula.parser.JavaCharStream;
51 import org.pentaho.reporting.libraries.formula.parser.ParseException;
52 import org.pentaho.reporting.libraries.formula.parser.Token;
53 import org.pentaho.reporting.libraries.formula.parser.TokenMgrError;
56 public final class SOFormulaParser extends ComponentBase
57 implements com.sun.star.report.meta.XFormulaParser, XServiceInfo
59 /* Need this to get around generics array creation restriction */
60 private static class StringOpcodeMap extends HashMap<Integer,FormulaOpCodeMapEntry> {}
62 public static final int SEPARATORS = 0;
63 public static final int ARRAY_SEPARATORS = 1;
64 public static final int UNARY_OPERATORS = 2;
65 public static final int BINARY_OPERATORS = 3;
66 public static final int FUNCTIONS = 4;
67 private final PropertySetMixin m_prophlp;
68 private static final String __serviceName = "com.sun.star.report.meta.FormulaParser";
69 private static final String OPERATORS = "org.pentaho.reporting.libraries.formula.operators.";
70 // attributes
71 final private List<FormulaOpCodeMapEntry> m_OpCodeMap = new ArrayList<FormulaOpCodeMapEntry>();
72 private XFormulaOpCodeMapper formulaOpCodeMapper = null;
73 private final Map<Integer,FormulaOpCodeMapEntry> parserAllOpCodes = new HashMap<Integer,FormulaOpCodeMapEntry>();
74 private final Map<String,FormulaOpCodeMapEntry> parserNames = new HashMap<String,FormulaOpCodeMapEntry>();
75 private final StringOpcodeMap[] groupOpCodes = new StringOpcodeMap[5];
76 private final List<FormulaOpCodeMapEntry> specialOpCodes = new ArrayList<FormulaOpCodeMapEntry>();
77 private int ownTokenCounter = 1000;
78 private final FormulaOpCodeMapEntry opCodePush;
79 private final FormulaParser parser;
81 public SOFormulaParser(final XComponentContext context)
84 final ClassLoader cl = java.lang.Thread.currentThread().getContextClassLoader();
85 Thread.currentThread().setContextClassLoader(this.getClass().getClassLoader());
87 parser = new FormulaParser();
88 try
90 final XFormulaOpCodeMapper mapper = UnoRuntime.queryInterface(XFormulaOpCodeMapper.class, context.getServiceManager().createInstanceWithContext("simple.formula.FormulaOpCodeMapperObj", context));
91 FormulaOpCodeMapEntry[] opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.FUNCTIONS);
92 final DefaultFormulaContext defaultContext = new DefaultFormulaContext();
93 final FunctionRegistry functionRegistry = defaultContext.getFunctionRegistry();
95 String[] names = functionRegistry.getFunctionNames();
96 addOpCodes(names, opCodes, FUNCTIONS);
97 names = getOperators(defaultContext, OPERATORS);
98 opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.UNARY_OPERATORS);
99 addOpCodes(names, opCodes, UNARY_OPERATORS);
100 opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.BINARY_OPERATORS);
101 addOpCodes(names, opCodes, BINARY_OPERATORS);
103 names = GeneratedFormulaParserConstants.tokenImage.clone();
104 for (int i = 0; i < names.length; i++)
106 final String token = names[i];
107 if (token != null && token.length() > 0 && token.charAt(0) == '"')
109 names[i] = token.substring(1, token.length() - 1);
112 opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.SEPARATORS);
113 addOpCodes(names, opCodes, SEPARATORS, false);
115 opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.ARRAY_SEPARATORS);
116 addOpCodes(names, opCodes, ARRAY_SEPARATORS, false);
118 opCodes = mapper.getAvailableMappings(FormulaLanguage.ODFF, FormulaMapGroup.SPECIAL);
120 for (int i = 0; i < opCodes.length; i++)
122 final FormulaOpCodeMapEntry opCode = opCodes[i];
123 parserAllOpCodes.put(opCode.Token.OpCode, opCode);
124 specialOpCodes.add(opCode);
127 catch (Exception ex)
129 ex.printStackTrace();
131 opCodePush = specialOpCodes.get(FormulaMapGroupSpecialOffset.PUSH);
132 Thread.currentThread().setContextClassLoader(cl);
133 // use the last parameter of the PropertySetMixin constructor
134 // for your optional attributes if necessary. See the documentation
135 // of the PropertySetMixin helper for further information.
136 // Ensure that your attributes are initialized correctly!
137 m_prophlp = new PropertySetMixin(context, this,
138 new Type(com.sun.star.report.meta.XFormulaParser.class), null);
141 // com.sun.star.sheet.XFormulaParser:
142 public com.sun.star.sheet.FormulaToken[] parseFormula(String aFormula, com.sun.star.table.CellAddress aReferencePos)
144 final ArrayList<FormulaToken> tokens = new ArrayList<FormulaToken>();
145 if (!"=".equals(aFormula))
147 String formula;
148 if (aFormula.charAt(0) == '=')
150 formula = aFormula.substring(1);
152 else
154 formula = aFormula;
156 final ArrayList<String> images = new ArrayList<String>();
159 int brackets = 0;
160 final GeneratedFormulaParserTokenManager tokenParser = new GeneratedFormulaParserTokenManager(new JavaCharStream(new StringReader(formula), 1, 1));
161 Token token = tokenParser.getNextToken();
162 while (token.kind != GeneratedFormulaParserConstants.EOF)
164 final FormulaToken formulaToken;
165 images.add(token.image);
166 final String upper = token.image.toUpperCase();
167 if (parserNames.containsKey(upper))
169 if ("(".equals(token.image))
171 brackets++;
173 else if (")".equals(token.image))
175 --brackets;
177 final FormulaOpCodeMapEntry opCode = parserNames.get(upper);
178 formulaToken = opCode.Token;
180 else if (token.kind == GeneratedFormulaParserConstants.WHITESPACE)
182 final FormulaOpCodeMapEntry opCode = specialOpCodes.get(FormulaMapGroupSpecialOffset.SPACES);
183 formulaToken = opCode.Token;
185 else
187 formulaToken = new FormulaToken();
188 formulaToken.OpCode = opCodePush.Token.OpCode;
189 formulaToken.Data = new Any(Type.STRING, token.image);
192 tokens.add(formulaToken);
193 token = tokenParser.getNextToken();
195 if (brackets > 0)
197 final FormulaOpCodeMapEntry opCode = parserNames.get(")");
198 while (brackets-- != 0)
200 formula = formula.concat(")");
201 images.add(")");
202 tokens.add(opCode.Token);
207 parser.parse(formula);
209 catch (ParseException ex)
211 boolean found = false;
212 // error occurred so all token must be bad
213 for (int i = 0; i < tokens.size(); i++)
215 if (!found && ex.currentToken != null && images.get(i).equals(ex.currentToken.image))
217 found = true;
219 if (found)
221 final FormulaToken dest = new FormulaToken();
222 dest.OpCode = specialOpCodes.get(FormulaMapGroupSpecialOffset.BAD).Token.OpCode;
223 dest.Data = new Any(Type.STRING, images.get(i));
224 tokens.remove(i);
225 tokens.add(i, dest);
229 catch (java.lang.Exception e)
232 catch (TokenMgrError e)
236 return tokens.toArray(new FormulaToken[tokens.size()]);
239 public String printFormula(com.sun.star.sheet.FormulaToken[] aTokens, com.sun.star.table.CellAddress aReferencePos)
241 final StringBuffer ret = new StringBuffer();
242 for (int i = 0; i < aTokens.length; i++)
244 final FormulaToken formulaToken = aTokens[i];
245 if (formulaToken.OpCode == opCodePush.Token.OpCode && !formulaToken.Data.equals(Any.VOID))
247 ret.append(formulaToken.Data);
249 else if (parserAllOpCodes.containsKey(formulaToken.OpCode))
251 final FormulaOpCodeMapEntry opCode = parserAllOpCodes.get(formulaToken.OpCode);
252 if (opCode.Name.length() > 0)
254 ret.append(opCode.Name);
256 else if (!formulaToken.Data.equals(Any.VOID))
258 ret.append(formulaToken.Data);
262 return ret.toString();
265 // com.sun.star.beans.XPropertySet:
266 public com.sun.star.beans.XPropertySetInfo getPropertySetInfo()
268 return m_prophlp.getPropertySetInfo();
271 public void setPropertyValue(String aPropertyName, Object aValue) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.beans.PropertyVetoException, com.sun.star.lang.IllegalArgumentException, com.sun.star.lang.WrappedTargetException
273 m_prophlp.setPropertyValue(aPropertyName, aValue);
276 public Object getPropertyValue(String aPropertyName) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
278 return m_prophlp.getPropertyValue(aPropertyName);
281 public void addPropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
283 m_prophlp.addPropertyChangeListener(aPropertyName, xListener);
286 public void removePropertyChangeListener(String aPropertyName, com.sun.star.beans.XPropertyChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
288 m_prophlp.removePropertyChangeListener(aPropertyName, xListener);
291 public void addVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
293 m_prophlp.addVetoableChangeListener(aPropertyName, xListener);
296 public void removeVetoableChangeListener(String aPropertyName, com.sun.star.beans.XVetoableChangeListener xListener) throws com.sun.star.beans.UnknownPropertyException, com.sun.star.lang.WrappedTargetException
298 m_prophlp.removeVetoableChangeListener(aPropertyName, xListener);
301 // com.sun.star.report.meta.XFormulaParser:
302 public com.sun.star.sheet.FormulaOpCodeMapEntry[] getOpCodeMap()
304 return m_OpCodeMap.toArray(new FormulaOpCodeMapEntry[m_OpCodeMap.size()]);
307 public void setOpCodeMap(com.sun.star.sheet.FormulaOpCodeMapEntry[] the_value)
311 public String getImplementationName()
313 return SOFormulaParser.class.getName();
316 public boolean supportsService(String sServiceName)
318 return sServiceName.equals(__serviceName);
321 public String[] getSupportedServiceNames()
323 return getServiceNames();
327 * This method is a simple helper function to used in the static component initialisation functions as well as
328 * in getSupportedServiceNames.
330 public static String[] getServiceNames()
332 return new String[]
334 __serviceName
338 public XFormulaOpCodeMapper getFormulaOpCodeMapper()
340 if (formulaOpCodeMapper == null)
342 formulaOpCodeMapper = new SOFormulaOpCodeMapper(this);
345 return formulaOpCodeMapper;
348 private void addOpCodes(String[] names, FormulaOpCodeMapEntry[] opCodes, int group)
350 addOpCodes(names, opCodes, group, true);
353 private void addOpCodes(String[] names, FormulaOpCodeMapEntry[] opCodes, int group, boolean add)
355 groupOpCodes[group] = new StringOpcodeMap();
356 for (int j = 0; j < names.length; j++)
358 FormulaOpCodeMapEntry opCode = null;
359 int i = 0;
360 for (; i < opCodes.length; i++)
362 opCode = opCodes[i];
363 if (names[j].equals(opCode.Name))
365 break;
368 if (i >= opCodes.length)
370 if (!add)
372 continue;
374 final FormulaToken token = new FormulaToken(ownTokenCounter++, Any.VOID);
375 opCode = new FormulaOpCodeMapEntry(names[j], token);
377 parserNames.put(names[j], opCode);
378 parserAllOpCodes.put(opCode.Token.OpCode, opCode);
379 groupOpCodes[group].put(opCode.Token.OpCode, opCode);
383 public Map<String,FormulaOpCodeMapEntry> getNames()
385 return parserNames;
388 public Map<Integer,FormulaOpCodeMapEntry> getGroup(int group)
390 return groupOpCodes[group];
393 private String[] getOperators(DefaultFormulaContext defaultContext, final String _kind)
395 final ArrayList<String> ops = new ArrayList<String>();
396 final Configuration configuration = defaultContext.getConfiguration();
397 final Iterator iter = configuration.findPropertyKeys(_kind);
398 while (iter.hasNext())
400 final String configKey = (String) iter.next();
401 if (!configKey.endsWith(".class"))
403 continue;
405 final String operatorClass = configuration.getConfigProperty(configKey);
406 if (operatorClass == null)
408 continue;
410 if (operatorClass.length() == 0)
412 continue;
414 final String tokenKey = configKey.substring(0, configKey.length() - ".class".length()) + ".token";
415 final String token = configuration.getConfigProperty(tokenKey);
416 if (token == null)
418 continue;
420 ops.add(token.trim());
422 return ops.toArray(new String[ops.size()]);
425 public List<FormulaOpCodeMapEntry> getSpecialOpCodes()
427 return specialOpCodes;