// Bart 20060831 -> i18n
/* **********************************************************************
* $Source: /home/cvs/nodus/src/com/bbn/openmap/plugin/WebImagePlugIn.java,v $
* $Revision: 1.2 $
* $Date: 2006-10-25 12:21:54 $
* $Author: jourquin $
*
* Code provided by Raj Singh from Syncline, rs@syncline.com
* Updates provided by Holger Kohler, Holger.Kohler@dsto.defence.gov.au
* *********************************************************************
*/
package com.bbn.openmap.plugin;
import java.awt.Component;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.geom.Point2D;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Iterator;
import java.util.Vector;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
import com.bbn.openmap.Environment;
import com.bbn.openmap.I18n;
import com.bbn.openmap.Layer;
import com.bbn.openmap.gui.MiniBrowser;
import com.bbn.openmap.image.ImageServerConstants;
import com.bbn.openmap.omGraphics.OMGraphicList;
import com.bbn.openmap.omGraphics.OMRaster;
import com.bbn.openmap.omGraphics.OMScalingRaster;
import com.bbn.openmap.omGraphics.OMWarpingImage;
import com.bbn.openmap.proj.LLXY;
import com.bbn.openmap.proj.Proj;
import com.bbn.openmap.proj.Projection;
import com.bbn.openmap.proj.coords.LatLonGCT;
import com.bbn.openmap.util.PropUtils;
/**
* This class asks for an image from a web server. How it asks for that image is
* what is abstract.
*/
public abstract class WebImagePlugIn extends AbstractPlugIn implements ImageServerConstants {
/** For convenience. */
protected PlugInLayer layer = null;
/** The last projection object received. */
protected Projection currentProjection = null;
/**
* Create the query to be sent to the server, based on current settings.
*/
public abstract String createQueryString(Projection p);
// I18N mechanism
static I18n i18n = Environment.getI18n();
public static Logger logger = Logger.getLogger("com.bbn.openmap.plugin.WebImagePlugIn");
/**
* The getRectangle call is the main call into the PlugIn module. The module
* is expected to fill the graphics list with objects that are within the
* screen parameters passed.
*
* @param p projection of the screen, holding scale, center coords, height,
* width.
*/
@Override
public OMGraphicList getRectangle(Projection p) {
OMGraphicList list = new OMGraphicList();
currentProjection = p;
Point2D ul = p.getUpperLeft();
Point2D lr = p.getLowerRight();
if (lr.getX() < ul.getX()) {
// Dateline! Make 2 queries, one for each side.
Point2D dateline1 = p.forward(ul.getY(), 179.9999);
Point2D dateline2 = p.forward(ul.getY(), -179.9999);
int w1 = (int) dateline1.getX();
int w2 = p.getWidth() - (int) dateline2.getX() - 1;
int h = p.getHeight();
Point2D c1 = p.inverse(w1 / 2, h / 2);
Point2D c2 = p.inverse((w2 / 2) + w1 + 1, h / 2);
Proj p1 = (Proj) p.makeClone();
Proj p2 = (Proj) p.makeClone();
p1.setCenter(c1);
p1.setWidth(w1);
p2.setCenter(c2);
p2.setWidth(w2);
fetchImageAndAddToList(p1, list);
fetchImageAndAddToList(p2, list);
} else {
fetchImageAndAddToList(p, list);
}
list.generate(p);
return list;
} // end prepare
/**
* Image fetching code, where the query is created based on the provided
* projection.
*
* @param p projection that image needs to cover
* @param list the OMGraphicList that any new image OMGraphics need to be
* added to for the map
*/
protected void fetchImageAndAddToList(Projection p, OMGraphicList list) {
String urlString = createQueryString(p);
if (logger.isLoggable(Level.FINE)) {
logger.fine("WebImagePlugIn.getRectangle() with \"" + urlString + "\"");
}
if (urlString == null) {
return;
}
java.net.URL url = null;
try {
url = new java.net.URL(urlString);
java.net.HttpURLConnection urlc = (java.net.HttpURLConnection) url.openConnection();
if (logger.isLoggable(Level.FINE)) {
logger.fine("url content type: " + urlc.getContentType());
}
if (urlc == null || urlc.getContentType() == null) {
logger.info(" unable to connect to " + urlString);
return;
}
// text
if (urlc.getContentType().startsWith("text")) {
java.io.BufferedReader bin = new java.io.BufferedReader(new java.io.InputStreamReader(urlc.getInputStream()));
String st;
StringBuffer message = new StringBuffer();
while ((st = bin.readLine()) != null) {
message.append(st);
}
logger.info("Received text from\n" + urlString + ":\n" + message.toString());
// image
} else if (urlc.getContentType().startsWith("image")) {
// the best way, no reconnect, but can be an
// additional 'in memory' image
InputStream in = urlc.getInputStream();
// ------- Testing without this
ByteArrayOutputStream out = new ByteArrayOutputStream();
int buflen = 2048; // 2k blocks
byte buf[] = new byte[buflen];
int len = -1;
while ((len = in.read(buf, 0, buflen)) != -1) {
out.write(buf, 0, len);
}
out.flush();
out.close();
ImageIcon ii = new ImageIcon(out.toByteArray());
// -------- To here, replaced by two lines below...
// DFD - I've seen problems with these lines below handling PNG
// images, and with some servers with some coverages, like there
// was something in the image under certain conditions that made
// it tough to view. So while it might be more memory efficient
// to do the code below, we'll error on the side of correctness
// until we figure out what's going on.
// FileCacheImageInputStream fciis = new
// FileCacheImageInputStream(in, null);
// BufferedImage ii = ImageIO.read(fciis);
if (p instanceof LLXY) {
// EPSG:4326, just put it on the screen
OMRaster image = new OMRaster((int) 0, (int) 0, ii);
list.add(image);
} else {
Point2D ul = p.getUpperLeft();
Point2D lr = p.getLowerRight();
OMScalingRaster omsr = new OMScalingRaster(ul.getY(), ul.getX(), lr.getY(), lr.getX(), ii);
OMWarpingImage omwi = new OMWarpingImage(omsr, LatLonGCT.INSTANCE);
list.add(omwi);
}
} // end if image
} catch (java.net.MalformedURLException murle) {
logger.warning("WebImagePlugIn: URL \"" + urlString + "\" is malformed.");
} catch (java.io.IOException ioe) {
handleMessage("Couldn't connect to " + getServerName());
}
}
protected void handleMessage(final String message) {
SwingUtilities.invokeLater(new Runnable() {
public void run() {
JOptionPane.showMessageDialog(null, getName() + ":\n\n "
+ message, "Connection Problem", JOptionPane.INFORMATION_MESSAGE);
}
});
}
public abstract String getServerName();
@Override
public java.awt.Component getGUI() {
JPanel panel = new JPanel(new GridLayout(0, 1));
JButton parameterButton = new JButton(i18n.get(WebImagePlugIn.class, "Adjust_Parameters", "Adjust Parameters"));
parameterButton.setActionCommand(Layer.DisplayPropertiesCmd);
if (layer != null) {
parameterButton.addActionListener(layer);
}
JButton viewQueryButton = new JButton(i18n.get(WebImagePlugIn.class, "View_Current_Query", "View Current Query"));
viewQueryButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (layer != null) {
String query = createQueryString(currentProjection);
Vector<String> queryStrings = PropUtils.parseMarkers(query, "&");
StringBuffer updatedQuery = new StringBuffer();
Iterator<String> it = queryStrings.iterator();
if (it.hasNext()) {
updatedQuery.append(it.next());
}
while (it.hasNext()) {
updatedQuery.append("&\n ");
updatedQuery.append(it.next());
}
if (logger.isLoggable(Level.FINE)) {
String stb = "Send Query to Browser";
String ok = "OK";
Object[] options = new Object[] { stb, ok };
int selectedVal = JOptionPane.showOptionDialog(null, updatedQuery, "Current Query for "
+ getName(), JOptionPane.YES_NO_OPTION, JOptionPane.INFORMATION_MESSAGE, null, options, ok);
if (selectedVal == 0) {
try {
new MiniBrowser(new URL(query));
} catch (MalformedURLException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
} else {
JOptionPane.showMessageDialog(null, updatedQuery.toString(), "Current Query for "
+ getName(), JOptionPane.INFORMATION_MESSAGE);
}
}
}
});
redrawButton.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent ae) {
if (layer != null) {
layer.doPrepare();
}
}
});
redrawButton.setEnabled(layer != null);
panel.add(parameterButton);
panel.add(viewQueryButton);
panel.add(redrawButton);
return panel;
}
protected JButton redrawButton = new JButton(i18n.get(WebImagePlugIn.class, "Query_Server", "Query Server"));
protected JOptionPane messageWindow = new JOptionPane();
/**
* Set the component that this PlugIn uses as a grip to the map.
*/
@Override
public void setComponent(Component comp) {
super.setComponent(comp);
if (comp instanceof PlugInLayer) {
layer = (PlugInLayer) comp;
} else {
layer = null;
}
redrawButton.setEnabled(layer != null);
}
} // end WMSPlugin