All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.jasperreports.components.map.fill.MapFillComponent Maven / Gradle / Ivy

There is a newer version: 6.21.3
Show newest version
/*
 * JasperReports - Free Java Reporting Library.
 * Copyright (C) 2001 - 2022 TIBCO Software Inc. All rights reserved.
 * http://www.jaspersoft.com
 *
 * Unless you have purchased a commercial license agreement from Jaspersoft,
 * the following license terms apply:
 *
 * This program is part of JasperReports.
 *
 * JasperReports is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * JasperReports is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public License
 * along with JasperReports. If not, see .
 */
package net.sf.jasperreports.components.map.fill;

import java.io.ByteArrayInputStream;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Map.Entry;

import javax.xml.parsers.DocumentBuilderFactory;

import org.jaxen.dom.DOMXPath;
import org.w3c.dom.Document;
import org.w3c.dom.Node;

import net.sf.jasperreports.components.items.ItemData;
import net.sf.jasperreports.components.map.MapComponent;
import net.sf.jasperreports.components.map.type.MapImageTypeEnum;
import net.sf.jasperreports.components.map.type.MapScaleEnum;
import net.sf.jasperreports.components.map.type.MapTypeEnum;
import net.sf.jasperreports.engine.JRComponentElement;
import net.sf.jasperreports.engine.JRException;
import net.sf.jasperreports.engine.JRGenericPrintElement;
import net.sf.jasperreports.engine.JRPrintElement;
import net.sf.jasperreports.engine.JRPropertiesHolder;
import net.sf.jasperreports.engine.JRPropertiesUtil;
import net.sf.jasperreports.engine.component.BaseFillComponent;
import net.sf.jasperreports.engine.component.FillContext;
import net.sf.jasperreports.engine.component.FillContextProvider;
import net.sf.jasperreports.engine.component.FillPrepareResult;
import net.sf.jasperreports.engine.fill.JRFillObjectFactory;
import net.sf.jasperreports.engine.fill.JRTemplateGenericElement;
import net.sf.jasperreports.engine.fill.JRTemplateGenericPrintElement;
import net.sf.jasperreports.engine.type.EvaluationTimeEnum;
import net.sf.jasperreports.engine.type.OnErrorTypeEnum;
import net.sf.jasperreports.engine.util.JRLoader;

/**
 * 
 * @author Teodor Danciu ([email protected])
 */
public class MapFillComponent extends BaseFillComponent implements FillContextProvider
{
	public static final String PLACE_URL_PREFIX = "https://maps.googleapis.com/maps/api/geocode/xml?address=";
	public static final String PLACE_URL_SUFFIX = "&output=xml&oe=utf8";
	public static final String DEFAULT_ENCODING = "UTF-8";
	public static final String STATUS_NODE = "/GeocodeResponse/status";
	public static final String LATITUDE_NODE = "/GeocodeResponse/result/geometry/location/lat";
	public static final String LONGITUDE_NODE = "/GeocodeResponse/result/geometry/location/lng";
	public static final String STATUS_OK = "OK";
	
	public static final String EXCEPTION_MESSAGE_KEY_NULL_OR_EMPTY_VALUE_NOT_ALLOWED = "components.map.null.or.empty.value.not.allowed";
	public static final String EXCEPTION_MESSAGE_KEY_NULL_OR_EMPTY_VALUES_NOT_ALLOWED = "components.map.null.or.empty.values.not.allowed";
	public static final String EXCEPTION_MESSAGE_KEY_INVALID_ADDRESS_COORDINATES = "components.map.invalid.address.coordinates";
	public static final String EXCEPTION_MESSAGE_KEY_ADDRESS_REQUEST_FAILED = "components.map.address.request.failed";
	
	private final MapComponent mapComponent;
	
	private Float latitude;
	private Float longitude;
	private String center;
	private Integer zoom;
	private String language;
	private MapTypeEnum mapType;
	private MapScaleEnum mapScale;
	private MapImageTypeEnum imageType;
	private OnErrorTypeEnum onErrorType;
	private String clientId;
	private String signature;
	private String key;
	private String googleVersion;
	private String version;
	private String reqParams;

	private List markerDataList;
	private List pathStyleList;
	private List pathDataList;
	private List> markers;
	private Map> styles;
	private List> paths;
	
	JRFillObjectFactory factory;
	
	public MapFillComponent(MapComponent map)
	{
		this.mapComponent = map;
	}
	
	public MapFillComponent(MapComponent map, JRFillObjectFactory factory)
	{
		this.mapComponent = map;
		this.factory = factory;
		this.reqParams = getReqParams();
		
		if(mapComponent.getMarkerDataList() != null){
			markerDataList = new ArrayList<>();
			for(ItemData markerData : mapComponent.getMarkerDataList()) {
				markerDataList.add(new FillPlaceItemData(this, markerData, factory));
			}
		}
		if(mapComponent.getPathStyleList() != null){
			pathStyleList = new ArrayList<>();
			for(ItemData pathStyle : mapComponent.getPathStyleList()) {
				pathStyleList.add(new FillStyleItemData(this, pathStyle, factory));
			}
		}
		if(mapComponent.getPathDataList() != null){
			pathDataList = new ArrayList<>();
			for(ItemData pathData : mapComponent.getPathDataList()) {
				pathDataList.add(new FillPlaceItemData(this, pathData, factory));
			}
		}
	}
	
	protected MapComponent getMap()
	{
		return mapComponent;
	}
	
	@Override
	public FillContext getFillContext()
	{
		return fillContext;
	}
	
	@Override
	public void evaluate(byte evaluation) throws JRException
	{
		if (isEvaluateNow())
		{
			evaluateMap(evaluation);
		}
	}
	
	protected void evaluateMap(byte evaluation) throws JRException
	{
		JRPropertiesHolder propertiesHolder = fillContext.getComponentElement().getParentProperties();
		JRPropertiesUtil util = JRPropertiesUtil.getInstance(fillContext.getFiller().getJasperReportsContext());
		clientId = util.getProperty(propertiesHolder, MapComponent.PROPERTY_CLIENT_ID);
		signature = util.getProperty(propertiesHolder, MapComponent.PROPERTY_SIGNATURE);
		key = util.getProperty(propertiesHolder, MapComponent.PROPERTY_KEY);
		googleVersion = util.getProperty(propertiesHolder, MapComponent.PROPERTY_GOOGLE_VERSION);
		@SuppressWarnings("deprecation")
		String depVersion = util.getProperty(propertiesHolder, MapComponent.PROPERTY_VERSION);
		version = depVersion;
		
		Number lat = (Number)fillContext.evaluate(mapComponent.getLatitudeExpression(), evaluation);
		latitude = lat == null ? null : lat.floatValue();
		
		Number lg = (Number)fillContext.evaluate(mapComponent.getLongitudeExpression(), evaluation);
		longitude = lg == null ? null : lg.floatValue();

		reqParams = getReqParams();
		
		if(latitude == null || longitude == null) {
			center = (String)fillContext.evaluate(mapComponent.getAddressExpression(), evaluation);
			Float[] coords = getCoords(center);
			if(coords != null && coords[0] != null && coords[1] != null){
				latitude = coords[0];
				longitude = coords[1];
			} else {
				throw 
					new JRException(
						EXCEPTION_MESSAGE_KEY_INVALID_ADDRESS_COORDINATES,  
						new Object[]{MapComponent.ITEM_PROPERTY_latitude, MapComponent.ITEM_PROPERTY_longitude} 
						);
			}
		}
		zoom = (Integer)fillContext.evaluate(mapComponent.getZoomExpression(), evaluation);
		zoom = zoom == null ? MapComponent.DEFAULT_ZOOM : zoom;
		if(mapComponent.getLanguageExpression() != null)
		{
			language = (String)fillContext.evaluate(mapComponent.getLanguageExpression(), evaluation);
		}
		else
		{
			Locale locale = fillContext.getReportLocale();
			if(locale != null)
			{
				language = locale.getLanguage();
			}
		}
		mapType = mapComponent.getMapType() == null? MapTypeEnum.ROADMAP : mapComponent.getMapType();
		mapScale = mapComponent.getMapScale();
		imageType = mapComponent.getImageType();

		if(markerDataList != null) {
			markers = new ArrayList<>();
			
			for(FillItemData markerData : markerDataList) {
				List> currentItemList = markerData.getEvaluateItems(evaluation);
				if(currentItemList != null && !currentItemList.isEmpty()){
					for(Map currentItem : currentItemList){
						if(currentItem != null){
							markers.add(currentItem);
						}
					}
				}
			}
		}
		
		if(pathDataList != null) {
			addPathStyles(evaluation);
			paths = new ArrayList<>();
			Map> pathIds = new HashMap<>();

			for(FillItemData pathData : pathDataList) {
				List> currentItemList = pathData.getEvaluateItems(evaluation);
				if(currentItemList != null && !currentItemList.isEmpty()){
					for(Map currentItem : currentItemList){
						if(currentItem != null){
							String pathName = currentItem.get(MapComponent.ITEM_PROPERTY_name) != null ? (String)currentItem.get(MapComponent.ITEM_PROPERTY_name) : MapComponent.DEFAULT_PATH_NAME;
							Map pathMap = null;
							if(pathIds.containsKey(pathName)){
								pathMap = pathIds.get(pathName);
							} else {
								pathMap = new HashMap<>();
								pathMap.put(MapComponent.PARAMETER_PATH_LOCATIONS, new ArrayList>());
								pathIds.put(pathName, pathMap);
								paths.add(pathMap);
							}
							setStyle((String)currentItem.get(MapComponent.ITEM_PROPERTY_style), pathMap);
							boolean coordSet = false;
							for(String key : currentItem.keySet()){
								if(!(MapComponent.ITEM_PROPERTY_name.equals(key) || MapComponent.ITEM_PROPERTY_style.equals(key))){
									if(MapComponent.ITEM_PROPERTY_latitude.equals(key) || MapComponent.ITEM_PROPERTY_longitude.equals(key)){
										if(!coordSet){
											if(currentItem.get(MapComponent.ITEM_PROPERTY_latitude) == null || currentItem.get(MapComponent.ITEM_PROPERTY_longitude) == null){
												throw new JRException(
														EXCEPTION_MESSAGE_KEY_NULL_OR_EMPTY_VALUES_NOT_ALLOWED,  
														new Object[]{MapComponent.ITEM_PROPERTY_latitude, MapComponent.ITEM_PROPERTY_longitude}
														);
											}
											Map location = new HashMap<>();
											location.put(MapComponent.ITEM_PROPERTY_latitude, currentItem.get(MapComponent.ITEM_PROPERTY_latitude));
											location.put(MapComponent.ITEM_PROPERTY_longitude, currentItem.get(MapComponent.ITEM_PROPERTY_longitude));
											((List>)pathMap.get(MapComponent.PARAMETER_PATH_LOCATIONS)).add(location);
											coordSet = true;
										}
									} else {
										pathMap.put(key, currentItem.get(key));
									}
								}
							}
						}
					}
				}
			}
		}
		onErrorType = mapComponent.getOnErrorType();
	}

	protected void addPathStyles(byte evaluation) throws JRException{
		styles = new HashMap<>();
		if (pathStyleList != null)
		{
			for(FillItemData styleData : pathStyleList){
				List> currentStyleList = styleData.getEvaluateItems(evaluation);
				if(currentStyleList != null && !currentStyleList.isEmpty()){
					for(Map currentStyle : currentStyleList){
						String styleName = (String)currentStyle.get(MapComponent.ITEM_PROPERTY_name);
						if(styleName == null){
							throw 
								new JRException(
									EXCEPTION_MESSAGE_KEY_NULL_OR_EMPTY_VALUE_NOT_ALLOWED,  
									new Object[]{MapComponent.ITEM_PROPERTY_name}
									);
						}
						Map styleMap = null;
						if(styles.containsKey(styleName)){
							styleMap = styles.get(styleName);
						} else {
							styleMap = new HashMap<>();
							styles.put(styleName, styleMap);
						}
						setStyle(currentStyle, styleMap);
					}
				}
			}
		}
	}
	
	protected void setStyle(String styleName, Map styleMap){
		if(styleName != null){
			Map parentStyleMap = styles.get(styleName);
			if(parentStyleMap != null && ! parentStyleMap.isEmpty()){
				String parentStyleName = (String)parentStyleMap.get(MapComponent.ITEM_PROPERTY_style);
				if(parentStyleName != null){
					setStyle(parentStyleName, styleMap);
				}
				setStyle(parentStyleMap, styleMap);
			}
		}
	}
	
	protected void setStyle(Map parentStyleMap, Map styleMap)
	{
		if (parentStyleMap != null)
		{
			for (Entry entry : parentStyleMap.entrySet())
			{
				String styleProperty = entry.getKey();
				if (
					!(MapComponent.ITEM_PROPERTY_name.equals(styleProperty) 
					|| MapComponent.ITEM_PROPERTY_latitude.equals(styleProperty) 
					|| MapComponent.ITEM_PROPERTY_longitude.equals(styleProperty))
					)
				{
					Object styleValue = entry.getValue();
					if (styleValue != null && styleValue.toString().length() > 0)
					{
						styleMap.put(styleProperty, styleValue);
					}
				}
			}
		}
	}
	
	protected boolean isEvaluateNow()
	{
		return mapComponent.getEvaluationTime() == EvaluationTimeEnum.NOW;
	}

	@Override
	public FillPrepareResult prepare(int availableHeight)
	{
		return FillPrepareResult.PRINT_NO_STRETCH;
//		return isEvaluateNow() && (latitude == null || longitude == null)  
//				? FillPrepareResult.NO_PRINT_NO_OVERFLOW
//				: FillPrepareResult.PRINT_NO_STRETCH;
	}

	@Override
	public JRPrintElement fill()
	{
		JRComponentElement element = fillContext.getComponentElement();
		JRTemplateGenericElement template = new JRTemplateGenericElement(
				fillContext.getElementOrigin(), 
				fillContext.getDefaultStyleProvider(),
				MapComponent.MAP_ELEMENT_TYPE);
		template = deduplicate(template);
		JRTemplateGenericPrintElement printElement = new JRTemplateGenericPrintElement(template, printElementOriginator);
		printElement.setUUID(element.getUUID());
		printElement.setX(element.getX());
		printElement.setY(fillContext.getElementPrintY());
		printElement.setWidth(element.getWidth());
		printElement.setHeight(element.getHeight());

		if (isEvaluateNow())
		{
			copy(printElement);
		}
		else
		{
			fillContext.registerDelayedEvaluation(printElement, 
					mapComponent.getEvaluationTime(), mapComponent.getEvaluationGroup());
		}
		
		return printElement;
	}

	@Override
	public void evaluateDelayedElement(JRPrintElement element, byte evaluation)
			throws JRException
	{
		evaluateMap(evaluation);
		copy((JRGenericPrintElement) element);
	}

	protected void copy(JRGenericPrintElement printElement)
	{
		printElement.setParameterValue(MapComponent.ITEM_PROPERTY_latitude, latitude);
		printElement.setParameterValue(MapComponent.ITEM_PROPERTY_longitude, longitude);
		printElement.setParameterValue(MapComponent.PARAMETER_ZOOM, zoom);
		String reqParams = getReqParams();
		if(reqParams != null && reqParams.trim().length() > 0) {
			printElement.setParameterValue(MapComponent.PARAMETER_REQ_PARAMS, reqParams);
		}
		if(mapType != null)
		{
			printElement.setParameterValue(MapComponent.ATTRIBUTE_MAP_TYPE, mapType.getName());
		}
		if(mapScale != null)
		{
			printElement.setParameterValue(MapComponent.ATTRIBUTE_MAP_SCALE, mapScale.getName());
		}
		if(imageType != null)
		{
			printElement.setParameterValue(MapComponent.ATTRIBUTE_IMAGE_TYPE, imageType.getName());
		}
		if(onErrorType != null)
		{
			printElement.setParameterValue(MapComponent.PARAMETER_ON_ERROR_TYPE, onErrorType.getName());
		}
		if(markers != null && !markers.isEmpty())
		{
			printElement.setParameterValue(MapComponent.PARAMETER_MARKERS, markers);
		}
		if(paths != null && !paths.isEmpty())
		{
			printElement.setParameterValue(MapComponent.PARAMETER_PATHS, paths);
		}
	}
	
	public String getReqParams()
	{
		if(reqParams == null)
		{
			String rParams = "";
			if(language != null && language.trim().length() > 0)
			{
				rParams += "&language=" + language;
			}
			if(clientId != null && clientId.trim().length() > 0) {
				rParams += "&client=" + clientId;
				if(signature != null) {
					rParams += "&signature=" + signature;
				}
			} else if(key != null && key.trim().length() > 0) {
				rParams += "&key=" + key;
			}
			
			if(googleVersion != null && googleVersion.trim().length() > 0) {
				rParams += "&v=" + googleVersion;
			} else if(version != null && version.trim().length() > 0 && (version.indexOf('.') < 0 || version.indexOf(".exp") > -1)) {
				// avoiding name collision of the version property
				rParams += "&v=" + version;
			}
			reqParams = rParams.length() == 0 ? null : rParams.substring(1);
		}
		return reqParams;
	}
	
	private Float[] getCoords(String address) throws JRException {
		Float[] coords = null;
		if(address != null) {
			try {
				String reqParams = getReqParams();
				reqParams = reqParams != null && reqParams.trim().length() > 0 ? "&" + reqParams : reqParams;
				String urlStr = PLACE_URL_PREFIX + URLEncoder.encode(address, DEFAULT_ENCODING) + reqParams + PLACE_URL_SUFFIX;
				URL url = new URL(urlStr);
				byte[] response = JRLoader.loadBytes(url);
				Document document = DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(new ByteArrayInputStream(response));
				Node statusNode = (Node) new DOMXPath(STATUS_NODE).selectSingleNode(document);
				String status = statusNode.getTextContent();
				if(STATUS_OK.equals(status)) {
					coords = new Float[2];
					Node latNode = (Node) new DOMXPath(LATITUDE_NODE).selectSingleNode(document);
					coords[0] = Float.valueOf(latNode.getTextContent());
					Node lngNode = (Node) new DOMXPath(LONGITUDE_NODE).selectSingleNode(document);
					coords[1] = Float.valueOf(lngNode.getTextContent());
				} else {
					throw 
						new JRException(
							EXCEPTION_MESSAGE_KEY_ADDRESS_REQUEST_FAILED,  
							new Object[]{status} 
							);
				}
			} catch (Exception e) {
				throw new JRException(e);
			}
		}
		return coords;
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy