001: /*
002: * ============================================================================
003: * GNU Lesser General Public License
004: * ============================================================================
005: *
006: * JasperReports - Free Java report-generating library.
007: * Copyright (C) 2001-2006 JasperSoft Corporation http://www.jaspersoft.com
008: *
009: * This library is free software; you can redistribute it and/or
010: * modify it under the terms of the GNU Lesser General Public
011: * License as published by the Free Software Foundation; either
012: * version 2.1 of the License, or (at your option) any later version.
013: *
014: * This library is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
017: * Lesser General Public License for more details.
018: *
019: * You should have received a copy of the GNU Lesser General Public
020: * License along with this library; if not, write to the Free Software
021: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307, USA.
022: *
023: * JasperSoft Corporation
024: * 303 Second Street, Suite 450 North
025: * San Francisco, CA 94107
026: * http://www.jaspersoft.com
027: */
028: package net.sf.jasperreports.engine;
029:
030: import java.awt.font.TextAttribute;
031: import java.io.File;
032: import java.io.InputStream;
033: import java.math.BigDecimal;
034: import java.math.BigInteger;
035: import java.net.URL;
036: import java.net.URLStreamHandlerFactory;
037: import java.text.DateFormat;
038: import java.text.NumberFormat;
039: import java.text.ParseException;
040: import java.util.ArrayList;
041: import java.util.Date;
042: import java.util.HashMap;
043: import java.util.LinkedList;
044: import java.util.List;
045: import java.util.Locale;
046: import java.util.Map;
047: import java.util.TimeZone;
048:
049: import net.sf.jasperreports.engine.base.JRBaseBox;
050: import net.sf.jasperreports.engine.export.data.BooleanTextValue;
051: import net.sf.jasperreports.engine.export.data.DateTextValue;
052: import net.sf.jasperreports.engine.export.data.NumberTextValue;
053: import net.sf.jasperreports.engine.export.data.StringTextValue;
054: import net.sf.jasperreports.engine.export.data.TextValue;
055: import net.sf.jasperreports.engine.util.DefaultFormatFactory;
056: import net.sf.jasperreports.engine.util.FormatFactory;
057: import net.sf.jasperreports.engine.util.JRClassLoader;
058: import net.sf.jasperreports.engine.util.JRDataUtils;
059: import net.sf.jasperreports.engine.util.JRFontUtil;
060: import net.sf.jasperreports.engine.util.JRLoader;
061: import net.sf.jasperreports.engine.util.JRProperties;
062: import net.sf.jasperreports.engine.util.JRResourcesUtil;
063: import net.sf.jasperreports.engine.util.JRStyledText;
064: import net.sf.jasperreports.engine.util.JRStyledTextParser;
065:
066: import org.xml.sax.SAXException;
067:
068: /**
069: * @author Teodor Danciu (teodord@users.sourceforge.net)
070: * @version $Id: JRAbstractExporter.java 1824 2007-08-23 14:19:12Z teodord $
071: */
072: public abstract class JRAbstractExporter implements JRExporter {
073:
074: //FIXMENOW this would make the applet require logging library
075: //private final static Log log = LogFactory.getLog(JRAbstractExporter.class);
076:
077: /**
078: *
079: */
080: protected Map parameters = new HashMap();
081:
082: /**
083: *
084: */
085: protected List jasperPrintList = null;
086: protected JasperPrint jasperPrint = null;
087: protected boolean isModeBatch = true;
088: protected int startPageIndex = 0;
089: protected int endPageIndex = 0;
090: protected int globalOffsetX = 0;
091: protected int globalOffsetY = 0;
092: protected ClassLoader classLoader = null;
093: protected boolean classLoaderSet = false;
094: protected URLStreamHandlerFactory urlHandlerFactory = null;
095: protected boolean urlHandlerFactorySet = false;
096:
097: /**
098: *
099: */
100: private LinkedList elementOffsetStack = new LinkedList();
101: private int elementOffsetX = globalOffsetX;
102: private int elementOffsetY = globalOffsetY;
103:
104: private Map penBoxes = new HashMap();//FIXMENOW is this working properly? forecolor is not part of the key
105:
106: /**
107: *
108: */
109: protected final JRStyledTextParser styledTextParser = new JRStyledTextParser();
110:
111: /**
112: *
113: */
114: protected Map dateFormatCache = new HashMap();
115: protected Map numberFormatCache = new HashMap();
116:
117: /**
118: *
119: */
120: protected JRAbstractExporter() {
121: }
122:
123: /**
124: *
125: */
126: public void reset() {
127: parameters = new HashMap();
128: elementOffsetStack = new LinkedList();
129: penBoxes = new HashMap();
130: }
131:
132: /**
133: *
134: */
135: public void setParameter(JRExporterParameter parameter, Object value) {
136: parameters.put(parameter, value);
137: }
138:
139: /**
140: *
141: */
142: public Object getParameter(JRExporterParameter parameter) {
143: return parameters.get(parameter);
144: }
145:
146: /**
147: *
148: */
149: public void setParameters(Map parameters) {
150: this .parameters = parameters;
151: }
152:
153: /**
154: *
155: */
156: public Map getParameters() {
157: return parameters;
158: }
159:
160: /**
161: *
162: */
163: protected String getStringParameter(JRExporterParameter parameter,
164: String property) {
165: if (parameters.containsKey(parameter)) {
166: return (String) parameters.get(parameter);
167: } else {
168: return JRProperties.getProperty(jasperPrint
169: .getPropertiesMap(), property);
170: }
171: }
172:
173: /**
174: *
175: */
176: protected String getStringParameterOrDefault(
177: JRExporterParameter parameter, String property) {
178: if (parameters.containsKey(parameter)) {
179: String value = (String) parameters.get(parameter);
180: if (value == null) {
181: return JRProperties.getProperty(property);
182: } else {
183: return value;
184: }
185: } else {
186: return JRProperties.getProperty(jasperPrint
187: .getPropertiesMap(), property);
188: }
189: }
190:
191: /**
192: *
193: */
194: protected boolean getBooleanParameter(
195: JRExporterParameter parameter, String property,
196: boolean defaultValue) {
197: if (parameters.containsKey(parameter)) {
198: Boolean booleanValue = (Boolean) parameters.get(parameter);
199: if (booleanValue == null) {
200: return JRProperties.getBooleanProperty(property);
201: } else {
202: return booleanValue.booleanValue();
203: }
204: } else {
205: return JRProperties.getBooleanProperty(jasperPrint
206: .getPropertiesMap(), property, defaultValue);
207: }
208: }
209:
210: /**
211: *
212: */
213: protected int getIntegerParameter(JRExporterParameter parameter,
214: String property, int defaultValue) {
215: if (parameters.containsKey(parameter)) {
216: Integer integerValue = (Integer) parameters.get(parameter);
217: if (integerValue == null) {
218: return JRProperties.getIntegerProperty(property);
219: } else {
220: return integerValue.intValue();
221: }
222: } else {
223: return JRProperties.getIntegerProperty(jasperPrint
224: .getPropertiesMap(), property, defaultValue);
225: }
226: }
227:
228: /**
229: *
230: */
231: public abstract void exportReport() throws JRException;
232:
233: /**
234: *
235: */
236: protected void setOffset() {
237: Integer offsetX = (Integer) parameters
238: .get(JRExporterParameter.OFFSET_X);
239: if (offsetX != null) {
240: globalOffsetX = offsetX.intValue();
241: } else {
242: globalOffsetX = 0;
243: }
244:
245: Integer offsetY = (Integer) parameters
246: .get(JRExporterParameter.OFFSET_Y);
247: if (offsetY != null) {
248: globalOffsetY = offsetY.intValue();
249: } else {
250: globalOffsetY = 0;
251: }
252:
253: elementOffsetX = globalOffsetX;
254: elementOffsetY = globalOffsetY;
255: }
256:
257: /**
258: *
259: */
260: protected void setExportContext() {
261: classLoaderSet = false;
262: urlHandlerFactorySet = false;
263:
264: classLoader = (ClassLoader) parameters
265: .get(JRExporterParameter.CLASS_LOADER);
266: if (classLoader != null) {
267: JRResourcesUtil.setThreadClassLoader(classLoader);
268: classLoaderSet = true;
269: }
270:
271: urlHandlerFactory = (URLStreamHandlerFactory) parameters
272: .get(JRExporterParameter.URL_HANDLER_FACTORY);
273: if (urlHandlerFactory != null) {
274: JRResourcesUtil
275: .setThreadURLHandlerFactory(urlHandlerFactory);
276: urlHandlerFactorySet = true;
277: }
278: }
279:
280: /**
281: *
282: */
283: protected void resetExportContext() {
284: if (classLoaderSet) {
285: JRResourcesUtil.resetClassLoader();
286: }
287:
288: if (urlHandlerFactorySet) {
289: JRResourcesUtil.resetThreadURLHandlerFactory();
290: }
291: }
292:
293: /**
294: * @deprecated replaced by {@link #setExportContext() setExportContext}
295: */
296: protected void setClassLoader() {
297: setExportContext();
298: }
299:
300: /**
301: * @deprecated replaced by {@link #resetExportContext() resetExportContext}
302: */
303: protected void resetClassLoader() {
304: resetExportContext();
305: }
306:
307: /**
308: *
309: */
310: protected void setInput() throws JRException {
311: jasperPrintList = (List) parameters
312: .get(JRExporterParameter.JASPER_PRINT_LIST);
313: if (jasperPrintList == null) {
314: isModeBatch = false;
315:
316: jasperPrint = (JasperPrint) parameters
317: .get(JRExporterParameter.JASPER_PRINT);
318: if (jasperPrint == null) {
319: InputStream is = (InputStream) parameters
320: .get(JRExporterParameter.INPUT_STREAM);
321: if (is != null) {
322: jasperPrint = (JasperPrint) JRLoader.loadObject(is);
323: } else {
324: URL url = (URL) parameters
325: .get(JRExporterParameter.INPUT_URL);
326: if (url != null) {
327: jasperPrint = (JasperPrint) JRLoader
328: .loadObject(url);
329: } else {
330: File file = (File) parameters
331: .get(JRExporterParameter.INPUT_FILE);
332: if (file != null) {
333: jasperPrint = (JasperPrint) JRLoader
334: .loadObject(file);
335: } else {
336: String fileName = (String) parameters
337: .get(JRExporterParameter.INPUT_FILE_NAME);
338: if (fileName != null) {
339: jasperPrint = (JasperPrint) JRLoader
340: .loadObject(fileName);
341: } else {
342: throw new JRException(
343: "No input source supplied to the exporter.");
344: }
345: }
346: }
347: }
348: }
349:
350: jasperPrintList = new ArrayList();
351: jasperPrintList.add(jasperPrint);
352: } else {
353: isModeBatch = true;
354:
355: if (jasperPrintList.size() == 0) {
356: throw new JRException(
357: "Empty input source supplied to the exporter in batch mode.");
358: }
359:
360: jasperPrint = (JasperPrint) jasperPrintList.get(0);
361: }
362: }
363:
364: /**
365: *
366: */
367: protected void setPageRange() throws JRException {
368: int lastPageIndex = -1;
369: if (jasperPrint.getPages() != null) {
370: lastPageIndex = jasperPrint.getPages().size() - 1;
371: }
372:
373: Integer start = (Integer) parameters
374: .get(JRExporterParameter.START_PAGE_INDEX);
375: if (start == null) {
376: startPageIndex = 0;
377: } else {
378: startPageIndex = start.intValue();
379: if (startPageIndex < 0 || startPageIndex > lastPageIndex) {
380: throw new JRException(
381: "Start page index out of range : "
382: + startPageIndex + " of "
383: + lastPageIndex);
384: }
385: }
386:
387: Integer end = (Integer) parameters
388: .get(JRExporterParameter.END_PAGE_INDEX);
389: if (end == null) {
390: endPageIndex = lastPageIndex;
391: } else {
392: endPageIndex = end.intValue();
393: if (endPageIndex < startPageIndex
394: || endPageIndex > lastPageIndex) {
395: throw new JRException("End page index out of range : "
396: + endPageIndex + " (" + startPageIndex + " : "
397: + lastPageIndex + ")");
398: }
399: }
400:
401: Integer index = (Integer) parameters
402: .get(JRExporterParameter.PAGE_INDEX);
403: if (index != null) {
404: int pageIndex = index.intValue();
405: if (pageIndex < 0 || pageIndex > lastPageIndex) {
406: throw new JRException("Page index out of range : "
407: + pageIndex + " of " + lastPageIndex);
408: }
409: startPageIndex = pageIndex;
410: endPageIndex = pageIndex;
411: }
412: }
413:
414: /**
415: *
416: */
417: protected JRStyledText getStyledText(JRPrintText textElement,
418: boolean setBackcolor) {
419: JRStyledText styledText = null;
420:
421: String text = textElement.getText();
422: if (text != null) {
423: Map attributes = new HashMap();
424: attributes.putAll(JRFontUtil.setAttributes(attributes,
425: textElement));
426: attributes.put(TextAttribute.FOREGROUND, textElement
427: .getForecolor());
428: if (setBackcolor
429: && textElement.getMode() == JRElement.MODE_OPAQUE) {
430: attributes.put(TextAttribute.BACKGROUND, textElement
431: .getBackcolor());
432: }
433:
434: if (textElement.isStyledText()) {
435: try {
436: styledText = styledTextParser.parse(attributes,
437: text);
438: } catch (SAXException e) {
439: //ignore if invalid styled text and treat like normal text
440: }
441: }
442:
443: if (styledText == null) {
444: styledText = new JRStyledText();
445: styledText.append(text);
446: styledText.addRun(new JRStyledText.Run(attributes, 0,
447: text.length()));
448: }
449: }
450:
451: return styledText;
452: }
453:
454: protected JRStyledText getStyledText(JRPrintText textElement) {
455: return getStyledText(textElement, true);
456: }
457:
458: /**
459: *
460: */
461: protected void setOutput() {
462: }
463:
464: /**
465: * Returns the X axis offset used for element export.
466: * <p>
467: * This method should be used istead of {@link #globalOffsetX globalOffsetX} when
468: * exporting elements.
469: *
470: * @return the X axis offset
471: */
472: protected int getOffsetX() {
473: return elementOffsetX;
474: }
475:
476: /**
477: * Returns the Y axis offset used for element export.
478: * <p>
479: * This method should be used istead of {@link #globalOffsetY globalOffsetY} when
480: * exporting elements.
481: *
482: * @return the Y axis offset
483: */
484: protected int getOffsetY() {
485: return elementOffsetY;
486: }
487:
488: /**
489: * Sets the offsets for exporting elements from a {@link JRPrintFrame frame}.
490: * <p>
491: * After the frame elements are exported, a call to {@link #restoreElementOffsets() popElementOffsets} is required
492: * so that the previous offsets are resored.
493: *
494: * @param frame
495: * @param relative
496: * @see #getOffsetX()
497: * @see #getOffsetY()
498: * @see #restoreElementOffsets()
499: */
500: protected void setFrameElementsOffset(JRPrintFrame frame,
501: boolean relative) {
502: if (relative) {
503: setElementOffsets(0, 0);
504: } else {
505: int topPadding = frame.getTopPadding();
506: int leftPadding = frame.getLeftPadding();
507:
508: setElementOffsets(
509: getOffsetX() + frame.getX() + leftPadding,
510: getOffsetY() + frame.getY() + topPadding);
511: }
512: }
513:
514: private void setElementOffsets(int offsetX, int offsetY) {
515: elementOffsetStack.addLast(new int[] { elementOffsetX,
516: elementOffsetY });
517:
518: elementOffsetX = offsetX;
519: elementOffsetY = offsetY;
520: }
521:
522: /**
523: * Restores offsets after a call to
524: * {@link #setFrameElementsOffset(JRPrintFrame, boolean) setFrameElementsOffset}.
525: */
526: protected void restoreElementOffsets() {
527: int[] offsets = (int[]) elementOffsetStack.removeLast();
528: elementOffsetX = offsets[0];
529: elementOffsetY = offsets[1];
530: }
531:
532: protected JRBox getBox(JRPrintGraphicElement element) {
533: byte pen = element.getPen();
534: Object key = new Byte(pen);
535: JRBox box = (JRBox) penBoxes.get(key);
536:
537: if (box == null) {
538: box = new JRBaseBox(pen, element.getForecolor());
539:
540: penBoxes.put(key, box);
541: }
542:
543: return box;
544: }
545:
546: protected String getTextFormatFactoryClass(JRPrintText text) {
547: String formatFactoryClass = text.getFormatFactoryClass();
548: if (formatFactoryClass == null) {
549: formatFactoryClass = jasperPrint.getFormatFactoryClass();
550: }
551: return formatFactoryClass;
552: }
553:
554: protected Locale getTextLocale(JRPrintText text) {
555: String localeCode = text.getLocaleCode();
556: if (localeCode == null) {
557: localeCode = jasperPrint.getLocaleCode();
558: }
559: return localeCode == null ? null : JRDataUtils
560: .getLocale(localeCode);
561: }
562:
563: protected TimeZone getTextTimeZone(JRPrintText text) {
564: String tzId = text.getTimeZoneId();
565: if (tzId == null) {
566: tzId = jasperPrint.getTimeZoneId();
567: }
568: return tzId == null ? null : JRDataUtils.getTimeZone(tzId);
569: }
570:
571: protected TextValue getTextValue(JRPrintText text, String textStr) {
572: TextValue textValue;
573: if (text.getValueClassName() == null) {
574: textValue = getTextValueString(text, textStr);
575: } else {
576: try {
577: Class valueClass = JRClassLoader
578: .loadClassForRealName(text.getValueClassName());
579: if (java.lang.Number.class.isAssignableFrom(valueClass)) {
580: textValue = getNumberCellValue(text, textStr);
581: } else if (Date.class.isAssignableFrom(valueClass)) {
582: textValue = getDateCellValue(text, textStr);
583: } else if (Boolean.class.equals(valueClass)) {
584: textValue = getBooleanCellValue(text, textStr);
585: } else {
586: textValue = getTextValueString(text, textStr);
587: }
588: } catch (ParseException e) {
589: //log.warn("Error parsing text value", e);
590: textValue = getTextValueString(text, textStr);
591: } catch (ClassNotFoundException e) {
592: //log.warn("Error loading text value class", e);
593: textValue = getTextValueString(text, textStr);
594: }
595: }
596: return textValue;
597: }
598:
599: protected TextValue getTextValueString(JRPrintText text,
600: String textStr) {
601: return new StringTextValue(textStr);
602: }
603:
604: protected TextValue getBooleanCellValue(JRPrintText text,
605: String textStr) {
606: Boolean value = null;
607: if (textStr != null || textStr.length() > 0) {
608: value = Boolean.valueOf(textStr);
609: }
610: return new BooleanTextValue(textStr, value);
611: }
612:
613: protected TextValue getDateCellValue(JRPrintText text,
614: String textStr) throws ParseException {
615: TextValue textValue;
616: String pattern = text.getPattern();
617: if (pattern == null || pattern.trim().length() == 0) {
618: textValue = getTextValueString(text, textStr);
619: } else {
620: DateFormat dateFormat = getDateFormat(
621: getTextFormatFactoryClass(text), pattern,
622: getTextLocale(text), getTextTimeZone(text));
623:
624: Date value = null;
625: if (textStr != null && textStr.length() > 0) {
626: value = dateFormat.parse(textStr);
627: }
628: textValue = new DateTextValue(textStr, value, pattern);
629: }
630: return textValue;
631: }
632:
633: protected TextValue getNumberCellValue(JRPrintText text,
634: String textStr) throws ParseException,
635: ClassNotFoundException {
636: TextValue textValue;
637: String pattern = text.getPattern();
638: if (pattern == null || pattern.trim().length() == 0) {
639: if (textStr != null && textStr.length() > 0) {
640: Number value = defaultParseNumber(textStr,
641: JRClassLoader.loadClassForRealName(text
642: .getValueClassName()));
643:
644: if (value != null) {
645: textValue = new NumberTextValue(textStr, value,
646: null);
647: } else {
648: textValue = getTextValueString(text, textStr);
649: }
650: } else {
651: textValue = new NumberTextValue(textStr, null, null);
652: }
653: } else {
654: NumberFormat numberFormat = getNumberFormat(
655: getTextFormatFactoryClass(text), pattern,
656: getTextLocale(text));
657:
658: Number value = null;
659: if (textStr != null && textStr.length() > 0) {
660: value = numberFormat.parse(textStr);
661: }
662: textValue = new NumberTextValue(textStr, value, pattern);
663: }
664: return textValue;
665: }
666:
667: protected Number defaultParseNumber(String textStr, Class valueClass) {
668: Number value = null;
669: try {
670: if (valueClass.equals(Byte.class)) {
671: value = Byte.valueOf(textStr);
672: } else if (valueClass.equals(Short.class)) {
673: value = Short.valueOf(textStr);
674: } else if (valueClass.equals(Integer.class)) {
675: value = Integer.valueOf(textStr);
676: } else if (valueClass.equals(Long.class)) {
677: value = Long.valueOf(textStr);
678: } else if (valueClass.equals(Float.class)) {
679: value = Float.valueOf(textStr);
680: } else if (valueClass.equals(Double.class)) {
681: value = Double.valueOf(textStr);
682: } else if (valueClass.equals(BigInteger.class)) {
683: value = new BigInteger(textStr);
684: } else if (valueClass.equals(BigDecimal.class)) {
685: value = new BigDecimal(textStr);
686: }
687: } catch (NumberFormatException e) {
688: //skip
689: }
690: return value;
691: }
692:
693: protected DateFormat getDateFormat(String formatFactoryClass,
694: String pattern, Locale lc, TimeZone tz) {
695: String key = formatFactoryClass + "|" + pattern + "|"
696: + JRDataUtils.getLocaleCode(lc) + "|"
697: + JRDataUtils.getTimeZoneId(tz);
698: DateFormat dateFormat = (DateFormat) dateFormatCache.get(key);
699: if (dateFormat == null) {
700: FormatFactory formatFactory = DefaultFormatFactory
701: .createFormatFactory(formatFactoryClass);//FIXMEFORMAT cache this too
702: dateFormat = formatFactory
703: .createDateFormat(pattern, lc, tz);
704: dateFormatCache.put(key, dateFormat);
705: }
706: return dateFormat;
707: }
708:
709: protected NumberFormat getNumberFormat(String formatFactoryClass,
710: String pattern, Locale lc) {
711: String key = formatFactoryClass + "|" + pattern + "|"
712: + JRDataUtils.getLocaleCode(lc);
713: NumberFormat numberFormat = (NumberFormat) numberFormatCache
714: .get(key);
715: if (numberFormat == null) {
716: FormatFactory formatFactory = DefaultFormatFactory
717: .createFormatFactory(formatFactoryClass);//FIXMEFORMAT cache this too
718: numberFormat = formatFactory
719: .createNumberFormat(pattern, lc);
720: dateFormatCache.put(key, numberFormat);
721: }
722: return numberFormat;
723: }
724:
725: }
|