/*************************************************** * * cismet GmbH, Saarbruecken, Germany * * ... and it just works. * ****************************************************/ package de.cismet.cismap.commons.wfsforms; import org.apache.log4j.Priority; import org.deegree.model.feature.FeatureCollection; import org.deegree.model.feature.FeatureProgressListener; import org.deegree.model.feature.GMLFeatureCollectionDocument; import org.jdom.Document; import org.jdom.Element; import org.jdom.Namespace; import org.jdom.input.SAXBuilder; import java.awt.Color; import java.awt.Component; import java.awt.EventQueue; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.io.InputStream; import java.io.InputStreamReader; import java.io.StringReader; import java.net.URL; import java.nio.charset.Charset; import java.util.HashMap; import java.util.Set; import java.util.Vector; import javax.swing.AbstractListModel; import javax.swing.ComboBoxModel; import javax.swing.JComboBox; import javax.swing.JComponent; import javax.swing.JProgressBar; import de.cismet.commons.security.AccessHandler.ACCESS_METHODS; import de.cismet.security.WebAccessManager; import de.cismet.tools.CismetThreadPool; import de.cismet.tools.CurrentStackTrace; import de.cismet.tools.StaticHtmlTools; /** * DOCUMENT ME! * * @author thorsten.hell@cismet.de * @version $Revision$, $Date$ */ public class WFSFormsListAndComboBoxModel extends AbstractListModel implements ComboBoxModel, FeatureProgressListener { //~ Static fields/initializers --------------------------------------------- private static final int MAX_RETRY = 3; //~ Instance fields -------------------------------------------------------- private final org.apache.log4j.Logger log = org.apache.log4j.Logger.getLogger(this.getClass()); private final String loadingMessage = org.openide.util.NbBundle.getMessage( WFSFormsListAndComboBoxModel.class, "WFSFormsListAndComboBoxModel.loadingMessage"); // NOI18N private final String errorMessage = org.openide.util.NbBundle.getMessage( WFSFormsListAndComboBoxModel.class, "WFSFormsListAndComboBoxModel.errorMessage"); // NOI18N private final Vector<WFSFormFeature> features = new Vector<WFSFormFeature>(); private final Vector<ActionListener> actionListener = new Vector<ActionListener>(); private FeatureCollection fc = null; private int estimatedFeatureCount = -1; private Object selectedValue; private boolean started = false; private boolean finished = false; private boolean error = false; private final WFSFormQuery query; private final JProgressBar progressBar; private final JComponent comp; private int max = 0; private HashMap latestReplacingValues = null; private int retryCounter = 0; //~ Constructors ----------------------------------------------------------- /** * Creates a new instance of WFSFormsListAndComboBoxModel. * * @param query DOCUMENT ME! * @param comp DOCUMENT ME! * @param progressBar DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public WFSFormsListAndComboBoxModel(final WFSFormQuery query, final JComponent comp, final JProgressBar progressBar) throws Exception { this(query, null, comp, progressBar); } /** * Creates a new WFSFormsListAndComboBoxModel object. * * @param query DOCUMENT ME! * @param replacingValues DOCUMENT ME! * @param comp DOCUMENT ME! * @param progressBar DOCUMENT ME! * * @throws Exception DOCUMENT ME! */ public WFSFormsListAndComboBoxModel(final WFSFormQuery query, final HashMap replacingValues, final JComponent comp, final JProgressBar progressBar) throws Exception { this.progressBar = progressBar; this.comp = comp; this.query = query; final Runnable t = new Thread("WFSFormsListAndComboBoxModel()") { @Override public void run() { refresh(replacingValues); } }; CismetThreadPool.execute(t); } //~ Methods ---------------------------------------------------------------- /** * DOCUMENT ME! * * @param replacingValues DOCUMENT ME! */ public void refresh(final HashMap replacingValues) { this.latestReplacingValues = replacingValues; // log.fatal("in refresh() --> EventQueue.isDispatchThread():"+EventQueue.isDispatchThread()); final GMLFeatureCollectionDocument gmlDocument = new GMLFeatureCollectionDocument(); try { if (!started) { EventQueue.invokeLater(new Runnable() { @Override public void run() { WFSFormsListAndComboBoxModel.this.comp.setEnabled(false); } }); if (WFSFormsListAndComboBoxModel.this.progressBar != null) { Color visible = WFSFormsListAndComboBoxModel.this.progressBar.getForeground(); visible = new Color(visible.getRed(), visible.getGreen(), visible.getBlue(), 255); final Color visibleCopy = visible; EventQueue.invokeLater(new Runnable() { @Override public void run() { comp.setToolTipText("Empfangen..."); // NOI18N WFSFormsListAndComboBoxModel.this.progressBar.setValue(0); WFSFormsListAndComboBoxModel.this.progressBar.setForeground(visibleCopy); WFSFormsListAndComboBoxModel.this.progressBar.setVisible(true); WFSFormsListAndComboBoxModel.this.progressBar.setIndeterminate(true); } }); } started = false; finished = false; error = false; String postString = query.getWfsQueryString(); if (replacingValues != null) { final Set keys = replacingValues.keySet(); if (log.isDebugEnabled()) { log.debug("replacingValues.keySet()" + replacingValues.keySet()); // NOI18N } for (final Object key : keys) { postString = postString.replaceAll((String)key, (String)replacingValues.get(key)); } } log.info("WFS Query:\n" + StaticHtmlTools.stringToHTMLString(postString)); // NOI18N final String modifiedString = getRightEncodedString(postString); // NOI18N // final String modifiedString = getRightEncodedString(new String( // postString.getBytes("UTF-8"), // "ISO-8859-1")); // NOI18N try { if (log.isDebugEnabled()) { log.debug("in EDT:" + EventQueue.isDispatchThread()); // NOI18N } final InputStream resp = WebAccessManager.getInstance() .doRequest(new URL(query.getServerUrl()), modifiedString, ACCESS_METHODS.POST_REQUEST); if (WFSFormsListAndComboBoxModel.this.progressBar != null) { EventQueue.invokeLater(new Runnable() { @Override public void run() { WFSFormsListAndComboBoxModel.this.progressBar.setIndeterminate(true); } }); } if (log.isDebugEnabled()) { log.debug("Start parsing of " + WFSFormsListAndComboBoxModel.this.query.getId()); // NOI18N } started = true; EventQueue.invokeLater(new Runnable() { @Override public void run() { WFSFormsListAndComboBoxModel.this.fireContentsChanged( WFSFormsListAndComboBoxModel.this, 0, 0); } }); final long start = System.currentTimeMillis(); // FileReader reader = new FileReader("request"); gmlDocument.load(new InputStreamReader( resp, Charset.forName("UTF-8")), "http://dummyURL"); // NOI18N // gmlDocument.load(new InputStreamReader(new // FileInputStream("request"),Charset.forName("iso-8859-1")),"http://dummyURL"); gmlDocument.addFeatureProgressListener(this); max = gmlDocument.getFeatureCount(); if (WFSFormsListAndComboBoxModel.this.progressBar != null) { EventQueue.invokeLater(new Runnable() { @Override public void run() { WFSFormsListAndComboBoxModel.this.progressBar.setIndeterminate(false); WFSFormsListAndComboBoxModel.this.progressBar.setMaximum(max); if (log.isDebugEnabled()) { log.debug("Feature count: " + max); // NOI18N } } }); } fc = gmlDocument.parse(); log.info("WFS Result:\n" + StaticHtmlTools.stringToHTMLString(gmlDocument.getAsPrettyString())); // NOI18N gmlDocument.removeFeatureProgressListener(this); if (log.isDebugEnabled()) { log.debug("Featurecollection " + fc); // NOI18N } for (int i = 0; i < fc.size(); ++i) { features.add(new WFSFormFeature(fc.getFeature(i), query)); if (log.isDebugEnabled()) { log.debug(i + ":" + features.get(i)); // NOI18N } } final long stop = System.currentTimeMillis(); if (log.isEnabledFor(Priority.INFO)) { log.info(((stop - start) / 1000.0) + " Sekunden dauerte das Parsen"); // NOI18N } if (log.isDebugEnabled()) { log.debug("Ended parsing of " + WFSFormsListAndComboBoxModel.this.query.getId()); // NOI18N } finished = true; error = false; selectedValue = null; WFSFormsListAndComboBoxModel.this.fireContentsChanged( WFSFormsListAndComboBoxModel.this, 0, fc.size() - 1); fireActionPerformed(null); if (WFSFormsListAndComboBoxModel.this.progressBar != null) { Color invisible = WFSFormsListAndComboBoxModel.this.progressBar.getForeground(); invisible = new Color(invisible.getRed(), invisible.getGreen(), invisible.getBlue(), 0); final Color invisibleCopy = invisible; EventQueue.invokeLater(new Runnable() { @Override public void run() { WFSFormsListAndComboBoxModel.this.progressBar.setForeground(invisibleCopy); } }); } EventQueue.invokeLater(new Runnable() { @Override public void run() { WFSFormsListAndComboBoxModel.this.comp.setEnabled(true); } }); comp.setToolTipText(""); } catch (Throwable t) { log.error("Error occured as sending a POST request", t); // NOI18N error = true; gmlDocument.removeFeatureProgressListener(this); reportRetrievalError(t); } } } catch (Exception e) { log.error("Error while loading the features.", e); // NOI18N gmlDocument.removeFeatureProgressListener(this); reportRetrievalError(e); } } /** * DOCUMENT ME! * * @param cause DOCUMENT ME! */ private void reportRetrievalError(final Throwable cause) { started = false; if (retryCounter < MAX_RETRY) { ++retryCounter; log.info("Retry " + retryCounter + " of " + MAX_RETRY); // NOI18N refresh(latestReplacingValues); } else { error = true; retryCounter = 0; EventQueue.invokeLater(new Runnable() { @Override public void run() { final Color oldForeground = progressBar.getForeground(); progressBar.setIndeterminate(false); progressBar.setForeground(Color.red); progressBar.setValue(progressBar.getMaximum()); // refresh view -> show error message final MouseAdapter retryListener = new MouseAdapter() { @Override public void mouseClicked(final MouseEvent e) { if (e.getClickCount() > 1) { comp.removeMouseListener(this); progressBar.setForeground(oldForeground); final Runnable t = new Thread( "WFSFormsListAndComboBoxModel reportRetrievalError()") { @Override public void run() { refresh(latestReplacingValues); } }; CismetThreadPool.execute(t); } } }; if (comp instanceof JComboBox) { final Component c = ((JComboBox)comp).getEditor().getEditorComponent(); if (c != null) { c.addMouseListener(retryListener); } } else { comp.addMouseListener(retryListener); } if ((cause != null) && (cause.getMessage() != null)) { comp.setToolTipText(cause.getMessage()); } fireContentsChanged(this, 0, 0); } }); } } /** * Returns the value at the specified index. * * @param index the requested index * * @return the value at <code>index</code> */ @Override public Object getElementAt(final int index) { if (!finished) { return loadingMessage; } else if ((index > -1) && (index < features.size())) { return features.get(index); } else { return "Kein Ergebnis"; } } /** * Returns the length of the list. * * @return the length of the list */ @Override public int getSize() { if (!finished) { // log.debug("Size=0"); return 0; } else { // log.debug("Size="+features.size()); return features.size(); } } /** * Set the selected item. The implementation of this method should notify all registered <code> * ListDataListener</code>s that the contents have changed. * * @param anItem the list object to select or <code>null</code> to clear the selection */ @Override public void setSelectedItem(final Object anItem) { if (log.isDebugEnabled()) { log.debug("setSelectedItem:" + ((anItem != null) ? anItem.getClass() : "null") + "::" + anItem); // NOI18N } selectedValue = anItem; } /** * Returns the selected item. * * @return The selected item or <code>null</code> if there is no selection */ @Override public Object getSelectedItem() { if (error) { return errorMessage; } else if (!finished) { return org.openide.util.NbBundle.getMessage( WFSFormsListAndComboBoxModel.class, "WFSFormListAndComboBoxModel.getSelectedItem().return"); // NOI18N } else if (getSize() == 0) { return ""; // NOI18N } else { return selectedValue; } } /** * DOCUMENT ME! * * @param s DOCUMENT ME! * * @return DOCUMENT ME! */ private int countFeatures(final String s) { // do this with jdom, because I don't know how to do it with the sax stuff try { final SAXBuilder builder = new SAXBuilder(false); final Document doc = builder.build(new StringReader(s)); final Element rootObject = doc.getRootElement(); return rootObject.getChildren("featureMember", Namespace.getNamespace("http://www.opengis.net/gml")).size(); // NOI18N } catch (Exception jex) { log.warn("error during featurecounting", jex); // NOI18N return -1; } } /** * DOCUMENT ME! * * @return DOCUMENT ME! */ public int getEstimatedFeatureCount() { return estimatedFeatureCount; } /** * DOCUMENT ME! * * @param estimatedFeatureCount DOCUMENT ME! */ public void setEstimatedFeatureCount(final int estimatedFeatureCount) { this.estimatedFeatureCount = estimatedFeatureCount; } @Override public void featureProgress(final int progress) { // count +=GMLFeatureCollectionDocument.PROGRESS_CONSTANT; if (WFSFormsListAndComboBoxModel.this.progressBar != null) { WFSFormsListAndComboBoxModel.this.progressBar.setValue(progress); } else { log.warn("No Progressbar in WFSGui", new CurrentStackTrace()); // NOI18N } } /** * DOCUMENT ME! */ public void featureLoadingFinished() { // WFSFormsListAndComboBoxModel.this.progressBar.setValue(max); } /** * DOCUMENT ME! */ public void featureProgress() { } /** * DOCUMENT ME! * * @param a DOCUMENT ME! */ public void addActionListener(final ActionListener a) { actionListener.add(a); } /** * DOCUMENT ME! * * @param a DOCUMENT ME! */ public void removeActionListener(final ActionListener a) { actionListener.remove(a); } /** * DOCUMENT ME! * * @param e DOCUMENT ME! */ public void fireActionPerformed(final ActionEvent e) { for (final ActionListener a : actionListener) { a.actionPerformed(e); } } /** * DOCUMENT ME! * * @param s DOCUMENT ME! * * @return DOCUMENT ME! */ private String getRightEncodedString(final String s) { // try { // return new String(s.getBytes("UTF-8"), "ISO-8859-1"); // } // catch (Exception e){ // log.error("Fehler beim KOnvertieren",e); // return null; // } String ret = s; ret = ret.replaceAll("ä", "ä"); ret = ret.replaceAll("Ä", "Ä"); ret = ret.replaceAll("ö", "ö"); ret = ret.replaceAll("Ö", "Ö"); ret = ret.replaceAll("ü", "ü"); ret = ret.replaceAll("Ü", "Ü"); ret = ret.replaceAll("ß", "ß"); return ret; } }