/***************************************************
*
* cismet GmbH, Saarbruecken, Germany
*
* ... and it just works.
*
****************************************************/
/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package de.cismet.cismap.commons;
import java.awt.Image;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.TreeMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
import de.cismet.cismap.commons.features.Feature;
import de.cismet.cismap.commons.gui.MappingComponent;
import de.cismet.cismap.commons.gui.layerwidget.ActiveLayerModel;
import de.cismet.cismap.commons.gui.piccolo.PFeature;
import de.cismet.cismap.commons.gui.piccolo.eventlistener.PrintTemplateFeature;
import de.cismet.cismap.commons.gui.printing.PrintingSettingsWidget;
import de.cismet.cismap.commons.gui.printing.PrintingWidget;
import de.cismet.cismap.commons.interaction.CismapBroker;
import de.cismet.cismap.commons.raster.wms.SlidableWMSServiceLayerGroup;
import de.cismet.cismap.commons.retrieval.AbstractRetrievalService;
import de.cismet.cismap.commons.retrieval.RepaintEvent;
import de.cismet.cismap.commons.retrieval.RepaintListener;
import de.cismet.cismap.commons.retrieval.RetrievalEvent;
import de.cismet.cismap.commons.retrieval.RetrievalService;
/**
* DOCUMENT ME!
*
* @author thorsten
* @version $Revision$, $Date$
*/
public class HeadlessMapProvider {
//~ Static fields/initializers ---------------------------------------------
private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(HeadlessMapProvider.class);
private static final double FEATURE_RESOLUTION_FACTOR = 125.0d;
//~ Enums ------------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public enum DominatingDimension {
//~ Enum constants -----------------------------------------------------
SIZE, BOUNDINGBOX
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public enum NotificationLevel {
//~ Enum constants -----------------------------------------------------
TIP, INFO, SUCCESS, EXPERT, WARN, ERROR, ERROR_REASON, UNLOCKED
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public enum RoundingPrecision {
//~ Enum constants -----------------------------------------------------
NO_ROUNDING, TENTH, HUNDRETH, THOUSANDTH
}
//~ Instance fields --------------------------------------------------------
MappingComponent map = new MappingComponent(false);
ActiveLayerModel mappingModel = new ActiveLayerModel();
XBoundingBox boundingBox = null;
private double minimumScaleDenominator = 0;
private double imgScaleDenominator;
private List<PropertyChangeListener> propertyChangeListener = new ArrayList<PropertyChangeListener>();
private HeadlessMapProvider.DominatingDimension dominatingDimension = HeadlessMapProvider.DominatingDimension.SIZE;
private HeadlessMapProvider.RoundingPrecision roundScaleTo = HeadlessMapProvider.RoundingPrecision.NO_ROUNDING;
private boolean centerMapOnResize = false;
private double printingResolution = 0;
private double resolution = 72.0;
private double featureResolutionFactor = PrintingSettingsWidget.FEATURE_RESOLUTION_FACTOR;
private Object requestingObject;
//~ Constructors -----------------------------------------------------------
/**
* Creates a new HeadlessMapProvider object.
*/
public HeadlessMapProvider() {
map.setResizeEventActivated(false);
map.setInternalLayerWidgetAvailable(false);
if (CismapBroker.getInstance().getMappingComponent() != null) {
// adopt the mapping configuration from the main MappingComponent
// Set the default Crs
final List<Crs> crsList = CismapBroker.getInstance().getMappingComponent().getCrsList();
final String defaultCrs = CismapBroker.getInstance().getDefaultCrs();
XBoundingBox homeBoundingBox = null;
boolean defaultCrsFound = false;
for (final Crs crs : crsList) {
if (crs.getCode().equals(defaultCrs)) {
mappingModel.setSrs(crs);
defaultCrsFound = true;
break;
}
}
if (!defaultCrsFound) {
LOG.warn("Default crs not found. Use EPSG:25832");
mappingModel.setSrs(new Crs("EPSG:25832", "", "", true, true));
}
if (CismapBroker.getInstance().getMappingComponent().getMappingModel().getInitialBoundingBox()
instanceof XBoundingBox) {
boundingBox = (XBoundingBox)CismapBroker.getInstance().getMappingComponent().getMappingModel()
.getInitialBoundingBox();
}
final HashMap homeMap =
((ActiveLayerModel)CismapBroker.getInstance().getMappingComponent().getMappingModel())
.getHomeBoundingBoxes();
final Set keys = homeMap.keySet();
for (final Object key : keys) {
homeBoundingBox = (XBoundingBox)homeMap.get(key);
mappingModel.addHome(homeBoundingBox);
}
if (mappingModel.getInitialBoundingBox() == null) {
LOG.error("Default home boundingBox not found");
if (homeBoundingBox != null) {
LOG.warn("Calculate home bounding box from " + homeBoundingBox);
try {
final CrsTransformer transformer = new CrsTransformer(defaultCrs);
homeBoundingBox = transformer.transformBoundingBox(homeBoundingBox);
mappingModel.addHome(homeBoundingBox);
} catch (Exception e) {
LOG.error("Cannot calculate home bounding box", e);
}
}
}
} else {
// set default values for test purposes
// Set the default Crs
mappingModel.setSrs(new Crs("EPSG:35833", "EPSG:35833", "EPSG:35833", true, true));
boundingBox = new XBoundingBox(33298653.1, 5994912.610934, 33308958.598, 5999709.97916, "EPSG:35833", true);
mappingModel.addHome(boundingBox);
}
// set the model
map.setMappingModel(mappingModel);
map.setSize(500, 500);
// initial positioning of the map
map.setAnimationDuration(0);
}
//~ Methods ----------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Object getRequestingObject() {
return requestingObject;
}
/**
* DOCUMENT ME!
*
* @param requestingObject DOCUMENT ME!
*/
public void setRequestingObject(final Object requestingObject) {
this.requestingObject = requestingObject;
}
/**
* DOCUMENT ME!
*
* @return the featureResolutionFactor
*/
public double getFeatureResolutionFactor() {
return featureResolutionFactor;
}
/**
* DOCUMENT ME!
*
* @param featureResolutionFactor the featureResolutionFactor to set
*/
public void setFeatureResolutionFactor(final double featureResolutionFactor) {
this.featureResolutionFactor = featureResolutionFactor;
}
/**
* Creates a HeadlessMapProvider and adds the raster layers and feature layers from the mapping component to it.
*
* @param mappingComponent DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public static HeadlessMapProvider createHeadlessMapProviderAndAddLayers(final MappingComponent mappingComponent) {
final HeadlessMapProvider headlessMapProvider = new HeadlessMapProvider();
((ActiveLayerModel)headlessMapProvider.getMappingComponent().getMappingModel()).setSrs(
mappingComponent.getMappingModel().getSrs());
final boolean infoNodeVisible = mappingComponent.isInfoNodesVisible();
headlessMapProvider.getMappingComponent().setInfoNodesVisible(infoNodeVisible);
// Raster Services
final TreeMap rasterServices = mappingComponent.getMappingModel().getRasterServices();
final List positionsRaster = new ArrayList(rasterServices.keySet());
Collections.sort(positionsRaster);
for (final Object position : positionsRaster) {
boolean addable = false;
final Object rasterService = rasterServices.get(position);
if ((rasterService instanceof RetrievalServiceLayer)
&& ((RetrievalServiceLayer)rasterService).isEnabled()) {
if ((rasterService instanceof PNodeProvider)
&& (((PNodeProvider)rasterService).getPNode() != null)
&& ((PNodeProvider)rasterService).getPNode().getVisible()) {
addable = true;
}
}
if (addable) {
headlessMapProvider.addLayer((RetrievalServiceLayer)rasterService);
} else {
LOG.warn(
"Layer can not be added to the headlessMapProvider as it is not an instance of RetrievalServiceLayer");
}
}
// Feature Services
// featureServices should always be empty
final TreeMap featureServices = mappingComponent.getMappingModel().getFeatureServices();
final List positionsFeatures = new ArrayList(featureServices.keySet());
Collections.sort(positionsFeatures);
for (final Object position : positionsFeatures) {
final Object featureService = featureServices.get(position);
if (featureService instanceof RetrievalServiceLayer) {
headlessMapProvider.addLayer((RetrievalServiceLayer)featureService);
} else {
LOG.warn(
"Feature can not be added to the headlessMapProvider as it is not an instance of RetrievalServiceLayer");
}
}
if (mappingComponent.isFeatureCollectionVisible()) {
// Features
for (final Feature f : mappingComponent.getFeatureCollection().getAllFeatures()) {
final boolean infoNodeExpanded = mappingComponent.getPFeatureHM().get(f).isInfoNodeExpanded();
if (!(f instanceof PrintTemplateFeature)) {
headlessMapProvider.addFeature(f);
if (infoNodeExpanded) {
final PFeature pf = headlessMapProvider.map.getPFeatureHM().get(f);
if (pf != null) {
pf.setInfoNodeExpanded(true);
}
}
}
}
}
return headlessMapProvider;
}
/**
* DOCUMENT ME!
*
* @return the printingResolution
*/
public double getPrintingResolution() {
return printingResolution;
}
/**
* DOCUMENT ME!
*
* @param printingResolution the printingResolution to set
*/
public void setPrintingResolution(final double printingResolution) {
this.printingResolution = printingResolution;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public MappingComponent getMappingComponent() {
return map;
}
/**
* Adds a PropertyChangeListener that will notify about the progress of the map building.
*
* @param listener the listener to add
*/
public void addPropertyChangeListener(final PropertyChangeListener listener) {
propertyChangeListener.add(listener);
}
/**
* Removes a PropertyChangeListener that will notify about the progress of the map building.
*
* @param listener the listener to remove
*/
public void removePropertyChangeListener(final PropertyChangeListener listener) {
propertyChangeListener.remove(listener);
}
/**
* add a feature to the HeadlessMapProvider.
*
* @param f the feature to add
*/
public void addFeature(final Feature f) {
map.getFeatureCollection().addFeature(f);
}
/**
* add a collection of features to the HeadlessMapProvider.
*
* @param featureCollection the feature collection to add
*/
public void addFeatures(final Collection<? extends Feature> featureCollection) {
map.getFeatureCollection().addFeatures(featureCollection);
}
/**
* Add a layer to the HeadlessMapProvider. A clone of the given layer is added to the model.
*
* @param layer the layer to add
*/
public void addLayer(final RetrievalServiceLayer layer) {
if (layer instanceof AbstractRetrievalService) {
final AbstractRetrievalService l = ((AbstractRetrievalService)layer).cloneWithoutRetrievalListeners();
// TODO remove this hack
if (l instanceof SlidableWMSServiceLayerGroup) {
((SlidableWMSServiceLayerGroup)l).setPrintMode(true);
}
mappingModel.addLayer((RetrievalServiceLayer)l);
} else {
mappingModel.addLayer(layer);
}
}
/**
* set the bounding box of the HeadlessMapProvider.
*
* @param boundingBox the new BoundingBox of the map
*/
public void setBoundingBox(final XBoundingBox boundingBox) {
this.boundingBox = boundingBox;
}
/**
* DOCUMENT ME!
*
* @param crs DOCUMENT ME!
*/
public void setCrs(final Crs crs) {
mappingModel.setSrs(crs);
}
/**
* Don't know what the idea was behind this method ;-) maybe take the 72dpi from jasper and recalculate the pixels
* then call the next method.
*
* @param dpi DOCUMENT ME!
* @param widthInMillimeters DOCUMENT ME!
* @param heightInMilimeters DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Image getImage(final int dpi, final double widthInMillimeters, final double heightInMilimeters) {
return null;
}
/**
* This is the method called when you need to fill in a report: for jasper with (72 as basedpi and widzth and height
* with the dimension of the image in the report
*
* @param baseDpi DOCUMENT ME!
* @param targetDpi DOCUMENT ME!
* @param widthInPixels DOCUMENT ME!
* @param heightInPixels DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public Future<Image> getImage(final int baseDpi,
final int targetDpi,
final double widthInPixels,
final double heightInPixels) {
printingResolution = targetDpi / CismapBroker.getInstance().getMappingComponent().getFeaturePrintingDpi();
final int imageWidth = (int)((double)widthInPixels / (double)baseDpi
* (double)targetDpi);
final int imageHeight = (int)((double)heightInPixels / (double)baseDpi
* (double)targetDpi);
map.setStickyFeatureCorrectionFactor(printingResolution);
resolution = targetDpi;
return getImage(imageWidth, imageHeight);
}
/**
* this is the most important function. all other getImage functions will call this function
*
* @param widthPixels DOCUMENT ME!
* @param heightPixels DOCUMENT ME!
*
* @return A future object that can provide an image
*/
public Future<Image> getImage(final int widthPixels, final int heightPixels) {
if (boundingBox == null) {
boundingBox = (XBoundingBox)mappingModel.getHomeBoundingBoxes().get(mappingModel.getDefaultHomeSrs());
LOG.warn("No BoundingBox was set explicitly. Will use the Home-BoundingBox");
}
// Check Ratio
int correctedWidthPixels = widthPixels;
int correctedHeightPixels = heightPixels;
XBoundingBox correctedBoundingBox = boundingBox;
correctedBoundingBox = new XBoundingBox(boundingBox.getX1(),
boundingBox.getY1(),
boundingBox.getX2(),
boundingBox.getY2(),
boundingBox.getSrs(),
boundingBox.isMetric());
final double pixelRelation = ((double)widthPixels / (double)heightPixels);
final double boundingBoxRelation = (boundingBox.getWidth() / boundingBox.getHeight());
if (pixelRelation != boundingBoxRelation) {
if (dominatingDimension == HeadlessMapProvider.DominatingDimension.SIZE) {
// adjusting the BoundingBox so that the old box would sit in the center of the new box
if (boundingBoxRelation < pixelRelation) {
final double boundingBoxWidth = (widthPixels * boundingBox.getHeight()) / heightPixels;
if (centerMapOnResize) {
final double changedWidth = Math.abs(boundingBoxWidth - boundingBox.getWidth());
correctedBoundingBox.setX2(correctedBoundingBox.getX2() + (changedWidth / 2));
correctedBoundingBox.setX1(correctedBoundingBox.getX1() - (changedWidth / 2));
} else {
correctedBoundingBox.setX2(correctedBoundingBox.getX1() + boundingBoxWidth);
}
} else {
final double boundingBoxHeight = (heightPixels * boundingBox.getWidth()) / widthPixels;
if (centerMapOnResize) {
final double changedHeight = Math.abs(boundingBoxHeight - boundingBox.getHeight());
correctedBoundingBox.setY2(correctedBoundingBox.getY2() + (changedHeight / 2));
correctedBoundingBox.setY1(correctedBoundingBox.getY1() - (changedHeight / 2));
} else {
correctedBoundingBox.setY2(correctedBoundingBox.getY1() + boundingBoxHeight);
}
}
} else if (dominatingDimension == HeadlessMapProvider.DominatingDimension.BOUNDINGBOX) {
// adjusting width and height
if (boundingBoxRelation < pixelRelation) {
correctedHeightPixels = (int)((widthPixels * boundingBox.getHeight()) / boundingBox.getWidth());
} else {
correctedWidthPixels = (int)((heightPixels * boundingBox.getWidth()) / boundingBox.getHeight());
}
}
}
map.setSize(correctedWidthPixels, correctedHeightPixels);
map.setNewViewBounds(null);
map.gotoBoundingBox(correctedBoundingBox, true, true, 0, false);
waitUntilGotoBoundingBoxIsComplete();
// check the minimum map scale condition
if ((minimumScaleDenominator > 0) && (map.getScaleDenominator() < minimumScaleDenominator)) {
if (LOG.isDebugEnabled()) {
LOG.debug("map scale of " + map.getScaleDenominator() + " is less than the configured minimum scale ( "
+ minimumScaleDenominator + "). Using minimim scale");
}
final BoundingBox bb = map.getBoundingBoxFromScale(minimumScaleDenominator);
correctedBoundingBox = new XBoundingBox(bb.getX1(),
bb.getY1(),
bb.getX2(),
bb.getY2(),
boundingBox.getSrs(),
boundingBox.isMetric());
map.setNewViewBounds(null);
map.gotoBoundingBox(correctedBoundingBox, true, true, 0, false);
waitUntilGotoBoundingBoxIsComplete();
}
// check if we have to round up the scale to a certain precision
if (roundScaleTo != HeadlessMapProvider.RoundingPrecision.NO_ROUNDING) {
double scale = 0;
if (roundScaleTo == HeadlessMapProvider.RoundingPrecision.TENTH) {
scale = Math.round((map.getScaleDenominator() / 10) + 0.5d) * 10;
} else if (roundScaleTo == HeadlessMapProvider.RoundingPrecision.HUNDRETH) {
scale = Math.round((map.getScaleDenominator() / 100) + 0.5d) * 100;
} else if (roundScaleTo == HeadlessMapProvider.RoundingPrecision.THOUSANDTH) {
scale = Math.round((map.getScaleDenominator() / 1000) + 0.5d) * 1000;
}
final BoundingBox bb = map.getBoundingBoxFromScale(scale);
correctedBoundingBox = new XBoundingBox(bb.getX1(),
bb.getY1(),
bb.getX2(),
bb.getY2(),
boundingBox.getSrs(),
boundingBox.isMetric());
map.setNewViewBounds(null);
map.gotoBoundingBox(correctedBoundingBox, true, true, 0, false);
waitUntilGotoBoundingBoxIsComplete();
}
imgScaleDenominator = map.getScaleDenominator();
map.setFixedBoundingBox(correctedBoundingBox);
if (printingResolution == 0) {
map.setPrintingResolution(resolution / getFeatureResolutionFactor());
} else {
map.setPrintingResolution(printingResolution);
}
final HeadlessMapProvider.HeadlessMapProviderRetrievalListener listener =
new HeadlessMapProvider.HeadlessMapProviderRetrievalListener(
correctedWidthPixels,
correctedHeightPixels,
propertyChangeListener,
mappingModel.getFeatureServices().size()
+ mappingModel.getMapServices().size());
map.addRepaintListener(listener);
map.unlockWithoutReload();
if (mappingModel.getMapServices().size() > 0) {
map.queryServices();
} else {
listener.createImageFromFeatures();
}
return listener;
}
/**
* Waits until the last gotoBoundingBox method of the MappingComponent is completed. This does only work, if
* setNewViewBounds(null) was invoked, before the gotoBoundingBox invocation and the history flag mus be true
*/
private void waitUntilGotoBoundingBoxIsComplete() {
while (map.getViewBounds() == null) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
// nothing to do
}
}
}
/**
* Generates the image and waits for the result. This method does not work in edt.
*
* @param widthPixels DOCUMENT ME!
* @param heightPixels DOCUMENT ME!
*
* @return An image of the map
*
* @throws ExecutionException DOCUMENT ME!
* @throws InterruptedException DOCUMENT ME!
*/
public Image getImageAndWait(final int widthPixels, final int heightPixels) throws ExecutionException,
InterruptedException {
return getImage(widthPixels, heightPixels).get();
}
/**
* This is the method called when you need to fill in a report: for jasper with (72 as basedpi and widzth and height
* with the dimension of the image in the report.
*
* @param basedpi DOCUMENT ME!
* @param targetDpi DOCUMENT ME!
* @param widthInPixels DOCUMENT ME!
* @param heightInPixels DOCUMENT ME!
*
* @return An image of the map
*
* @throws ExecutionException DOCUMENT ME!
* @throws InterruptedException DOCUMENT ME!
*/
public Image getImageAndWait(final int basedpi,
final int targetDpi,
final double widthInPixels,
final double heightInPixels) throws ExecutionException, InterruptedException {
return getImage(basedpi, targetDpi, widthInPixels, heightInPixels).get();
}
/**
* The dominating dimension determines, what value is changed, when the image pixel ratio is adjusted to the
* coordinate ratio.
*
* @return the dominatingDimension
*/
public HeadlessMapProvider.DominatingDimension getDominatingDimension() {
return dominatingDimension;
}
/**
* Set the dominating dimension. The dominating dimension determines, what value is changed, when the image pixel
* ratio will be adjusted to the coordinate ratio
*
* @param dominatingDimension the dominatingDimension to set
*/
public void setDominatingDimension(final HeadlessMapProvider.DominatingDimension dominatingDimension) {
this.dominatingDimension = dominatingDimension;
}
/**
* DOCUMENT ME!
*
* @param minimumScaleDenominator DOCUMENT ME!
*/
public void setMinimumScaleDenomimator(final double minimumScaleDenominator) {
this.minimumScaleDenominator = minimumScaleDenominator;
}
/**
* DOCUMENT ME!
*
* @param b DOCUMENT ME!
*/
public void setCenterMapOnResize(final boolean b) {
centerMapOnResize = b;
}
/**
* DOCUMENT ME!
*
* @param rp DOCUMENT ME!
*/
public void setRoundScaleTo(final HeadlessMapProvider.RoundingPrecision rp) {
this.roundScaleTo = rp;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public double getImageScaleDenominator() {
return imgScaleDenominator;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
public BoundingBox getCurrentBoundingBoxFromMap() {
return map.getCurrentBoundingBoxFromCamera();
}
//~ Inner Classes ----------------------------------------------------------
/**
* This class uses the RetrievalLisener interface to build the map image and the Future interface to provide the map
* image.
*
* @version $Revision$, $Date$
*/
class HeadlessMapProviderRetrievalListener implements Future<Image>,
RepaintListener,
ErroneousRetrievalServiceProvider {
//~ Instance fields ----------------------------------------------------
int imageWidth;
int imageHeight;
private HashSet<RetrievalService> services;
private HashSet<Object> results;
private HashSet<RetrievalService> erroneous;
private boolean cancel = false;
private volatile boolean done = false;
private final ReentrantLock lock = new ReentrantLock();
private Condition condition = lock.newCondition();
private List<PropertyChangeListener> listener = new ArrayList<PropertyChangeListener>();
private int serviceCount = 0;
//~ Constructors -------------------------------------------------------
/**
* Creates a new HeadlessMapProviderRetrievalListener object.
*
* @param imageWidth the width of the image
* @param imageHeight the height of the image
* @param listener DOCUMENT ME!
* @param serviceCount DOCUMENT ME!
*/
public HeadlessMapProviderRetrievalListener(final int imageWidth,
final int imageHeight,
final List<PropertyChangeListener> listener,
final int serviceCount) {
this.imageWidth = imageWidth;
this.imageHeight = imageHeight;
services = new HashSet<RetrievalService>();
results = new HashSet<Object>();
erroneous = new HashSet<RetrievalService>();
this.listener = listener;
this.serviceCount = serviceCount;
}
//~ Methods ------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @param repaintEvent DOCUMENT ME!
*/
@Override
public synchronized void repaintStart(final RepaintEvent repaintEvent) {
final RetrievalEvent e = repaintEvent.getRetrievalEvent();
if (LOG.isDebugEnabled()) {
LOG.debug("start");
}
if (LOG.isDebugEnabled()) {
LOG.debug("retrievalStarted" + e.getRetrievalService()); // NOI18N
}
if (e.isInitialisationEvent()) {
LOG.error(e.getRetrievalService() + "[" + e.getRequestIdentifier()
+ "]: retrievalStarted ignored, initialisation event"); // NOI18N
return;
}
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalStarted(RetrievalEvent).msg",
new Object[] { e.getRetrievalService() }),
HeadlessMapProvider.NotificationLevel.INFO); // NOI18N
if (e.getRetrievalService() == null) {
System.out.println("service is null");
}
if (e.getRetrievalService() instanceof ServiceLayer) {
services.add(e.getRetrievalService());
}
}
/**
* DOCUMENT ME!
*
* @param repaintEvent DOCUMENT ME!
*/
@Override
public void repaintError(final RepaintEvent repaintEvent) {
final RetrievalEvent e = repaintEvent.getRetrievalEvent();
LOG.error(e.getRetrievalService() + "[" + e.getRequestIdentifier() + "]: retrievalError"); // NOI18N
if (e.isInitialisationEvent()) {
LOG.error(e.getRetrievalService() + "[" + e.getRequestIdentifier()
+ "]: retrievalError ignored, initialisation event"); // NOI18N
return;
}
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalError(RetrievalEvent).msg1",
new Object[] { e.getRetrievalService() }),
HeadlessMapProvider.NotificationLevel.ERROR); // NOI18N
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalError(RetrievalEvent).msg2"),
HeadlessMapProvider.NotificationLevel.ERROR_REASON,
e); // NOI18N
repaintEvent.getRetrievalEvent().setHasErrors(true);
repaintComplete(repaintEvent);
}
/**
* DOCUMENT ME!
*
* @param repaintEvent DOCUMENT ME!
*/
@Override
public synchronized void repaintComplete(final RepaintEvent repaintEvent) {
final RetrievalEvent e = repaintEvent.getRetrievalEvent();
if (LOG.isInfoEnabled()) {
LOG.info(e.getRetrievalService() + "[" + e.getRequestIdentifier() + "]: retrievalComplete"); // NOI18N
}
if (e.isInitialisationEvent()) {
LOG.error(e.getRetrievalService() + "[" + e.getRequestIdentifier()
+ "]: retrievalComplete ignored, initialisation event"); // NOI18N
return;
}
if (e.getRetrievalService() instanceof ServiceLayer) {
if (!e.isHasErrors()) {
results.add(e.getRetrievalService());
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg",
new Object[] { e.getRetrievalService() }),
HeadlessMapProvider.NotificationLevel.SUCCESS); // NOI18N
} else {
erroneous.add(e.getRetrievalService());
if (e.getRetrievedObject() instanceof Image) {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg2",
new Object[] { e.getRetrievalService() }),
HeadlessMapProvider.NotificationLevel.ERROR_REASON,
e); // NOI18N
}
}
}
if ((results.size() + erroneous.size()) == serviceCount) {
if (results.size() == serviceCount) {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg6"),
HeadlessMapProvider.NotificationLevel.SUCCESS); // NOI18N
} else if (services.isEmpty()) {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg7"),
HeadlessMapProvider.NotificationLevel.WARN); // NOI18N
} else {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg8"),
HeadlessMapProvider.NotificationLevel.WARN); // NOI18N
}
addFeaturesToTopLevelLayer();
if (erroneous.size() < results.size()) {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg4"),
HeadlessMapProvider.NotificationLevel.SUCCESS); // NOI18N
} else {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg5"),
HeadlessMapProvider.NotificationLevel.INFO); // NOI18N
}
LOG.info("Following layers were painted: " + results); // NOI18N
if (LOG.isDebugEnabled()) {
LOG.debug("services:" + services); // NOI18N
}
unlock();
}
}
/**
* DOCUMENT ME!
*
* @return a set of all layers, which cannot be retrieved
*/
@Override
public HashSet<RetrievalService> getErroneousLayer() {
return erroneous;
}
/**
* Creates an image of the features. This is required if the map does only contain features and no layer.
*/
public void createImageFromFeatures() {
addFeaturesToTopLevelLayer();
unlock();
}
/**
* Adds the features to the map image.
*/
private void addFeaturesToTopLevelLayer() {
// Add Existing Features as TopLevelLayer
if (map.isFeatureCollectionVisible()) {
try {
sendNotification(org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg3"),
HeadlessMapProvider.NotificationLevel.INFO); // NOI18N
} catch (Throwable t) {
LOG.error("Error while adding local features to the map", t); // NOI18N
}
} else {
final String localFeaturesNotAddedMessage = org.openide.util.NbBundle.getMessage(
PrintingWidget.class,
"PrintingWidget.retrievalComplete(RetrievalEvent).msg9");
sendNotification(localFeaturesNotAddedMessage, HeadlessMapProvider.NotificationLevel.INFO); // NOI18N
if (LOG.isDebugEnabled()) {
LOG.debug(localFeaturesNotAddedMessage);
}
}
}
/**
* Unlocks this object. This means that the map was created and the {@link get()} and
* {@link get(long, TimeUnit)} methods can provide a result.
*/
private void unlock() {
lock.lock();
try {
done = true;
condition.signalAll();
} finally {
lock.unlock();
sendNotification("", NotificationLevel.UNLOCKED);
}
}
/**
* Send a notification to all registered listeners.
*
* @param msg the message to send
* @param level the notification level
*/
private void sendNotification(final String msg, final HeadlessMapProvider.NotificationLevel level) {
sendNotification(msg, level, null);
}
/**
* Send a notification to all registered listeners.
*
* @param msg the message to send
* @param level the notification level
* @param e a RetrievalEvent
*/
private void sendNotification(final String msg,
final HeadlessMapProvider.NotificationLevel level,
final RetrievalEvent e) {
String prefix;
if ((msg != null) && (msg.trim().length() > 0)
&& (HeadlessMapProvider.this.requestingObject instanceof PrintTemplateFeature)
&& (map.getSpecialFeatureCollection(PrintTemplateFeature.class).size() > 1)) {
prefix = ((PrintTemplateFeature)HeadlessMapProvider.this.requestingObject).getName() + ": ";
} else {
prefix = "";
}
final PropertyChangeEvent evt = new PropertyChangeEvent(
HeadlessMapProvider.this,
"notification",
e,
new HeadlessMapProvider.NotificationMessage(prefix + msg, level));
for (final PropertyChangeListener tmpListener : listener) {
tmpListener.propertyChange(evt);
}
}
/**
* DOCUMENT ME!
*
* @param mayInterruptIfRunning DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
@Override
public boolean cancel(final boolean mayInterruptIfRunning) {
this.cancel = true;
return !done;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
@Override
public boolean isCancelled() {
return cancel;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*/
@Override
public boolean isDone() {
return done;
}
/**
* DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws InterruptedException DOCUMENT ME!
* @throws ExecutionException DOCUMENT ME!
*/
@Override
public Image get() throws InterruptedException, ExecutionException {
lock.lock();
try {
if (!isDone()) {
condition.await();
}
return map.getImage();
} finally {
lock.unlock();
}
}
/**
* DOCUMENT ME!
*
* @param timeout DOCUMENT ME!
* @param unit DOCUMENT ME!
*
* @return DOCUMENT ME!
*
* @throws InterruptedException DOCUMENT ME!
* @throws ExecutionException DOCUMENT ME!
* @throws TimeoutException DOCUMENT ME!
*/
@Override
public Image get(final long timeout, final TimeUnit unit) throws InterruptedException,
ExecutionException,
TimeoutException {
lock.lock();
try {
if (!isDone()) {
if (!condition.await(timeout, unit)) {
throw new TimeoutException();
}
}
return map.getImage();
} finally {
lock.unlock();
}
}
}
/**
* DOCUMENT ME!
*
* @version $Revision$, $Date$
*/
public class NotificationMessage {
//~ Instance fields ----------------------------------------------------
private String msg;
private HeadlessMapProvider.NotificationLevel level;
//~ Constructors -------------------------------------------------------
/**
* Creates a new NotificationMessage object.
*/
public NotificationMessage() {
}
/**
* Creates a new NotificationMessage object.
*
* @param msg DOCUMENT ME!
* @param level DOCUMENT ME!
*/
public NotificationMessage(final String msg, final HeadlessMapProvider.NotificationLevel level) {
this.msg = msg;
this.level = level;
}
//~ Methods ------------------------------------------------------------
/**
* DOCUMENT ME!
*
* @return the msg
*/
public String getMsg() {
return msg;
}
/**
* DOCUMENT ME!
*
* @param msg the msg to set
*/
public void setMsg(final String msg) {
this.msg = msg;
}
/**
* DOCUMENT ME!
*
* @return the level
*/
public HeadlessMapProvider.NotificationLevel getLevel() {
return level;
}
/**
* DOCUMENT ME!
*
* @param level the level to set
*/
public void setLevel(final HeadlessMapProvider.NotificationLevel level) {
this.level = level;
}
}
}