Java tutorial
/* * Copyright (c) 2001-2011 Convertigo SA. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Affero General Public License * as published by the Free Software Foundation; either version 3 * of the License, or (at your option) any later version. * * This program 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, see<http://www.gnu.org/licenses/>. * * $URL$ * $Author$ * $Revision$ * $Date$ */ package com.twinsoft.convertigo.eclipse.editors.connector; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.Enumeration; import java.util.EventObject; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.StringTokenizer; import javax.swing.event.EventListenerList; import javax.xml.transform.TransformerException; import org.apache.commons.httpclient.HttpStatus; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.viewers.ISelectionChangedListener; import org.eclipse.jface.viewers.ISelectionProvider; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.viewers.SelectionChangedEvent; import org.eclipse.jface.window.Window; import org.eclipse.jface.wizard.WizardDialog; import org.eclipse.swt.SWT; import org.eclipse.swt.custom.SashForm; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.layout.GridData; import org.eclipse.swt.layout.GridLayout; import org.eclipse.swt.widgets.Composite; import org.eclipse.swt.widgets.Display; import org.eclipse.swt.widgets.Label; import org.eclipse.swt.widgets.Text; import org.eclipse.swt.widgets.ToolBar; import org.eclipse.swt.widgets.ToolItem; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NodeList; import com.twinsoft.convertigo.beans.common.XPath; import com.twinsoft.convertigo.beans.connectors.HtmlConnector; import com.twinsoft.convertigo.beans.connectors.HttpConnector; import com.twinsoft.convertigo.beans.core.Connector; import com.twinsoft.convertigo.beans.core.Criteria; import com.twinsoft.convertigo.beans.core.DatabaseObject; import com.twinsoft.convertigo.beans.core.ScreenClass; import com.twinsoft.convertigo.beans.core.Statement; import com.twinsoft.convertigo.beans.core.StatementWithExpressions; import com.twinsoft.convertigo.beans.extractionrules.HtmlExtractionRule; import com.twinsoft.convertigo.beans.screenclasses.HtmlScreenClass; import com.twinsoft.convertigo.beans.statements.HTTPStatement; import com.twinsoft.convertigo.beans.statements.HandlerStatement; import com.twinsoft.convertigo.beans.statements.ScEntryHandlerStatement; import com.twinsoft.convertigo.beans.statements.ScExitHandlerStatement; import com.twinsoft.convertigo.beans.statements.ScHandlerStatement; import com.twinsoft.convertigo.beans.transactions.HtmlTransaction; import com.twinsoft.convertigo.eclipse.ConvertigoPlugin; import com.twinsoft.convertigo.eclipse.editors.CompositeEvent; import com.twinsoft.convertigo.eclipse.editors.CompositeListener; import com.twinsoft.convertigo.eclipse.editors.connector.htmlconnector.DomTreeComposite; import com.twinsoft.convertigo.eclipse.editors.connector.htmlconnector.HtmlXpathEvaluatorComposite; import com.twinsoft.convertigo.eclipse.editors.connector.htmlconnector.XpathEvaluatorComposite; import com.twinsoft.convertigo.eclipse.learnproxy.http.gui.HttpProxyEvent; import com.twinsoft.convertigo.eclipse.learnproxy.http.gui.HttpProxyEventListener; import com.twinsoft.convertigo.eclipse.moz.IWebViewerStudio; import com.twinsoft.convertigo.eclipse.moz.XulWebViewerImpl; import com.twinsoft.convertigo.eclipse.views.projectexplorer.ProjectExplorerView; import com.twinsoft.convertigo.eclipse.views.projectexplorer.model.ConnectorTreeObject; import com.twinsoft.convertigo.eclipse.views.projectexplorer.model.TransactionTreeObject; import com.twinsoft.convertigo.eclipse.views.projectexplorer.model.TreeObject; import com.twinsoft.convertigo.eclipse.wizards.new_object.NewObjectWizard; import com.twinsoft.convertigo.eclipse.wizards.new_statement.StatementGeneratorWizard; import com.twinsoft.convertigo.engine.Engine; import com.twinsoft.convertigo.engine.EngineEvent; import com.twinsoft.convertigo.engine.EngineException; import com.twinsoft.convertigo.engine.EngineListener; import com.twinsoft.convertigo.engine.KeyExpiredException; import com.twinsoft.convertigo.engine.MaxCvsExceededException; import com.twinsoft.convertigo.engine.ObjectWithSameNameException; import com.twinsoft.convertigo.engine.enums.HeaderName; import com.twinsoft.convertigo.engine.enums.MimeType; import com.twinsoft.convertigo.engine.parsers.DocumentCompletedListener; import com.twinsoft.convertigo.engine.parsers.HtmlParser; import com.twinsoft.convertigo.engine.parsers.SelectionChangedListener; import com.twinsoft.convertigo.engine.parsers.WebViewerTabManager; import com.twinsoft.convertigo.engine.util.GenericUtils; import com.twinsoft.convertigo.engine.util.StringUtils; import com.twinsoft.convertigo.engine.util.TwsCachedXPathAPI; import com.twinsoft.util.TextCodec; public class HtmlConnectorDesignComposite extends Composite implements EngineListener, ISelectionChangedListener, HttpProxyEventListener { private HtmlConnector htmlConnector = null; private HtmlScreenClass detectedScreenClass = null; private HtmlTransaction xmlizingTransaction = null; private HtmlTransaction runningTransaction = null; /** Parts of the editor */ private HtmlXpathEvaluatorComposite xpathEvaluator = null; private DomTreeComposite domTreeComp = null; /** Toolbar */ private ToolBar objectToolBar = null; private ToolBar learnToolBar = null; private ToolItem toolLearn = null; private ToolItem toolAccumulate = null; private ToolItem toolShowScreenclass = null; private ToolItem toolGenerateXml = null; private ToolItem toolStopTransaction = null; private ToolItem toggleAutoRefresh = null; private SashForm sashForm = null; private Composite upperPanel = null; private SashForm lowerSashForm = null; private WebViewerTabManager tabManager = null; private Image imageLearn = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/next_node.png")); private Image imageAccumulate = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/next_node.png")); private Image imageShowScreenclass = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/sync.png")); private Image imageAutoRefresh = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/autorefresh.png")); private Image imageGenerateXml = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/xml.png")); private Image imageStop = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/stop.d.png")); private Image imageDisableStop = new Image(Display.getCurrent(), getClass().getResourceAsStream("/com/twinsoft/convertigo/eclipse/editors/images/stop.png")); private Text currentAbsoluteXpath = null; private ProjectExplorerView projectExplorerView = null; private SelectionChangedListener selectionChangedListener = new SelectionChangedListener() { public void changed() { getWebViewer().setFocus(); Thread th = new Thread(new Runnable() { public void run() { final Document dom = domTreeComp.getCurrentDom(); Display.getDefault().asyncExec(new Runnable() { public void run() { try { String selectedXpath = getWebViewer().getSelectedXpath(); NodeList nl = getXpathApi().selectNodeList(dom, selectedXpath); if (nl.getLength() == 0) { boolean bOk = MessageDialog.openConfirm(null, "Html tree synchronization", "The selected element was'nt found in the current HTML tree, would you like to synchronize it with the current HTML page displayed ?"); if (bOk) { // Synchronize the HTML Tree domTreeComp.displayXhtml(getWebViewer().getDom()); // Hightlight the selected item selectedXpath = getWebViewer().getSelectedXpath(); } } setCurrentAbsoluteXpath(selectedXpath); domTreeComp.selectElementInTree(selectedXpath); } catch (TransformerException e) { ConvertigoPlugin.logException(e, "Xpath not valid"); } } }); } }); th.setName("Document completed Update"); th.start(); } }; public DocumentCompletedListener documentCompletedListener = new DocumentCompletedListener() { public void completed() { ConvertigoPlugin.logDebug2("(HtmlConnectorDesignComposite) document completed"); toolShowScreenclass.setEnabled(!htmlConnector.isLearning()); toolGenerateXml.setEnabled(!htmlConnector.isLearning()); if (toggleAutoRefresh.getSelection()) { Thread th = new Thread(new Runnable() { public void run() { Document dom = getWebViewer().getDom(); for (int i = 0; i < 10 && dom == null; i++) { try { Thread.sleep(500); } catch (InterruptedException e) { } dom = getWebViewer().getDom(); } if (dom != null) { final Document finalDom = dom; Display.getDefault().asyncExec(new Runnable() { public void run() { domTreeComp.displayXhtml(finalDom); } }); if (htmlConnector.isLearning()) { HtmlTransaction htmlTransaction = (HtmlTransaction) htmlConnector .getLearningTransaction(); htmlTransaction.setCurrentXmlDocument(dom); try { detectedScreenClass = htmlConnector.getCurrentScreenClass(); Engine.theApp.fireObjectDetected(new EngineEvent(detectedScreenClass)); ConvertigoPlugin .logDebug2("(HtmlConnectorDesignComposite) detected screen class '" + detectedScreenClass.getName() + "'"); } catch (EngineException e) { ConvertigoPlugin.logInfo("Engine exception occurs: " + e.getMessage()); } } } } }); th.setName("Document completed Update"); th.start(); } } }; public HtmlConnectorDesignComposite(Connector connector, Composite parent, int style) throws MaxCvsExceededException, KeyExpiredException { super(parent, style); htmlConnector = (HtmlConnector) connector; projectExplorerView = ConvertigoPlugin.getDefault().getProjectExplorerView(); // add ProjectExplorerView to the listeners of the associated html connector if (projectExplorerView != null) { projectExplorerView.addSelectionChangedListener(this); addCompositeListener(projectExplorerView); } // Set parser and add it as listener of change in HttpState HtmlParser htmlParser = new HtmlParser(null); htmlConnector.addHttpStateListener(htmlParser); htmlConnector.setHtmlParser(htmlParser); htmlConnector.context.htmlParser = htmlParser; try { initialize(); if (htmlConnector.context.httpState == null) { htmlConnector.resetHttpState(htmlConnector.context); } domTreeComp.getTwsDomTree().addMenuMaker(xpathEvaluator.makeXPathMenuMaker(true)); domTreeComp.getTwsDomTree().addMenuMaker(xpathEvaluator.makeStatementGeneratorsMenuMaker(true)); domTreeComp.getTwsDomTree().addKeyAccelerator(xpathEvaluator.makeXPathKeyAccelerator(true)); } catch (MaxCvsExceededException e) { // Remove ProjectExplorerView from listeners current composite view if (projectExplorerView != null) { projectExplorerView.removeSelectionChangedListener(this); removeCompositeListener(projectExplorerView); } // Release parser and remove it from HttpState listeners htmlConnector.removeHttpStateListener(htmlParser); htmlConnector.setHtmlParser(null); // Remove Studio context Engine.theApp.contextManager.remove(htmlConnector.context); dispose(); throw e; } catch (KeyExpiredException e) { // Remove ProjectExplorerView from listeners current composite view if (projectExplorerView != null) { projectExplorerView.removeSelectionChangedListener(this); removeCompositeListener(projectExplorerView); } // Release parser and remove it from HttpState listeners htmlConnector.removeHttpStateListener(htmlParser); htmlConnector.setHtmlParser(null); // Remove Studio context Engine.theApp.contextManager.remove(htmlConnector.context); dispose(); throw e; } // Registering as Engine listener Engine.theApp.addEngineListener(this); } public TwsCachedXPathAPI getXpathApi() { return htmlConnector.context.getXpathApi(); } private void initialize() throws MaxCvsExceededException, KeyExpiredException { setSize(new org.eclipse.swt.graphics.Point(435, 336)); GridLayout gl = new GridLayout(1, false); gl.horizontalSpacing = gl.verticalSpacing = gl.marginWidth = gl.marginHeight = 0; setLayout(gl); setBackground(Display.getCurrent().getSystemColor(SWT.COLOR_WIDGET_BACKGROUND)); Composite absoluteXpathPan = new Composite(this, SWT.BORDER); absoluteXpathPan.setLayoutData(new GridData(SWT.FILL, SWT.DEFAULT, true, false)); gl = new GridLayout(10, false); gl.horizontalSpacing = gl.verticalSpacing = gl.marginWidth = gl.marginHeight = 0; absoluteXpathPan.setLayout(gl); createToolBars(absoluteXpathPan); new Label(absoluteXpathPan, SWT.NONE).setText("Current selection : "); currentAbsoluteXpath = new Text(absoluteXpathPan, SWT.BORDER); currentAbsoluteXpath.setEditable(false); currentAbsoluteXpath.setLayoutData(new GridData(SWT.FILL, SWT.CENTER, true, false)); createSashForm(); } public void setCurrentAbsoluteXpath(String absoluteXpath) { currentAbsoluteXpath.setText(absoluteXpath); } public void close() { // Stop learning if needed stopLearn(); // Remove ProjectExplorerView from listeners current composite view if (projectExplorerView != null) { projectExplorerView.removeSelectionChangedListener(this); removeCompositeListener(projectExplorerView); } // Deregister as Engine listener Engine.theApp.removeEngineListener(this); // Release parser and remove it from HttpState listeners HtmlParser htmlParser = htmlConnector.getHtmlParser(); htmlConnector.removeHttpStateListener(htmlParser); htmlParser.release(); // Reset htmlConnector.context = null; htmlConnector.setCurrentXmlDocument(null); htmlConnector.setHtmlParser(null); } @Override public void dispose() { //TODO:imageAttrib.dispose(); //TODO:imageNode.dispose(); imageLearn.dispose(); imageAccumulate.dispose(); imageShowScreenclass.dispose(); imageGenerateXml.dispose(); super.dispose(); } private EventListenerList compositeListeners = new EventListenerList(); public void addCompositeListener(CompositeListener compositeListener) { compositeListeners.add(CompositeListener.class, compositeListener); } public void removeCompositeListener(CompositeListener compositeListener) { compositeListeners.remove(CompositeListener.class, compositeListener); } public void fireObjectSelected(CompositeEvent compositeEvent) { // Guaranteed to return a non-null array Object[] listeners = compositeListeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == CompositeListener.class) { ((CompositeListener) listeners[i + 1]).objectSelected(compositeEvent); } } } public void fireObjectChanged(CompositeEvent compositeEvent) { // Guaranteed to return a non-null array Object[] listeners = compositeListeners.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == CompositeListener.class) { ((CompositeListener) listeners[i + 1]).objectChanged(compositeEvent); } } } /** * This method initializes toolBar * */ private void createToolBars(Composite toolbars) { //Composite toolbars = new Composite(this, SWT.BORDER); //toolbars.setLayout(new GridLayout(4,false)); // auto refresh ToolBar toggleAutoRefreshToolbar = new ToolBar(toolbars, SWT.NONE); toggleAutoRefresh = new ToolItem(toggleAutoRefreshToolbar, SWT.CHECK); toggleAutoRefresh.setToolTipText("Toggle auto refresh domTree"); toggleAutoRefresh.setImage(imageAutoRefresh); toggleAutoRefresh.setSelection(true); toggleAutoRefresh.setEnabled(true); // DatabaseObject toolbar objectToolBar = new ToolBar(toolbars, SWT.NONE); toolShowScreenclass = new ToolItem(objectToolBar, SWT.PUSH); toolShowScreenclass.setToolTipText("Show current screen class"); toolShowScreenclass.setImage(imageShowScreenclass); toolShowScreenclass.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { showCurrentScreenClass(); } public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) { } }); toolShowScreenclass.setEnabled(false); toolGenerateXml = new ToolItem(objectToolBar, SWT.PUSH); toolGenerateXml.setImage(imageGenerateXml); toolGenerateXml.setToolTipText("Generate XML"); toolGenerateXml.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { generateXml(); } public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) { } }); toolGenerateXml.setEnabled(false); toolStopTransaction = new ToolItem(new ToolBar(toolbars, SWT.NONE), SWT.PUSH); toolStopTransaction.setDisabledImage(imageStop); toolStopTransaction.setToolTipText("Stop the current transaction"); toolStopTransaction.setImage(imageDisableStop); toolStopTransaction.setEnabled(false); toolStopTransaction.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { try { /*if (Engine.getProperty(EngineProperties.ConfigurationProperties.DOCUMENT_THREADING_USE_STOP_METHOD).equalsIgnoreCase("true")) { runningTransaction.runningThread.stop(); } else { runningTransaction.runningThread.bContinue = false; }*/ htmlConnector.context.abortRequestable(); } catch (NullPointerException npe) { // Silently ignore: means the runningTransaction pointer has been set to null // because of normal transaction termination... } } public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) { } }); // Learn toolbar learnToolBar = new ToolBar(toolbars, SWT.NONE); toolLearn = new ToolItem(learnToolBar, SWT.CHECK); toolLearn.setToolTipText("Learn"); toolLearn.setImage(imageLearn); toolLearn.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { if (toolLearn.getSelection()) { startLearn(); toolAccumulate.setEnabled(true); } else { stopLearn(); toolAccumulate.setSelection(false); toolAccumulate.setEnabled(false); } } public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) { } }); toolLearn.setEnabled(false); toolAccumulate = new ToolItem(learnToolBar, SWT.CHECK); toolAccumulate.setToolTipText("Accumulate learning mode"); toolAccumulate.setImage(imageAccumulate); toolAccumulate.addSelectionListener(new org.eclipse.swt.events.SelectionListener() { public void widgetSelected(org.eclipse.swt.events.SelectionEvent e) { if (toolAccumulate.getSelection()) { htmlConnector.setAccumulate(true); } else { htmlConnector.setAccumulate(false); } } public void widgetDefaultSelected(org.eclipse.swt.events.SelectionEvent e) { } }); toolAccumulate.setEnabled(false); new ToolItem(learnToolBar, SWT.SEPARATOR); } /** * This method initializes sashForm * @throws MaxCvsExceededException * @throws KeyExpiredException * */ private void createSashForm() throws MaxCvsExceededException, KeyExpiredException { sashForm = new SashForm(this, SWT.BORDER); sashForm.setOrientation(org.eclipse.swt.SWT.VERTICAL); sashForm.setLayoutData(new org.eclipse.swt.layout.GridData(SWT.FILL, SWT.FILL, true, true)); createComposite1(); xpathEvaluator = new HtmlXpathEvaluatorComposite(sashForm, SWT.NONE, this); sashForm.setWeights(new int[] { 80, 20 }); //sashForm.setSashWidth(3); } /** * This method initializes composite1 * @throws MaxCvsExceededException * @throws KeyExpiredException * */ private void createComposite1() throws MaxCvsExceededException, KeyExpiredException { GridLayout gl = new GridLayout(); gl.horizontalSpacing = gl.marginWidth = gl.marginHeight = gl.verticalSpacing = 0; upperPanel = new Composite(sashForm, SWT.NONE); upperPanel.setLayout(gl); createUpperSashForm(); } /** * This method initializes lowerSashForm * @throws MaxCvsExceededException * @throws KeyExpiredException * */ private void createUpperSashForm() throws MaxCvsExceededException, KeyExpiredException { lowerSashForm = new SashForm(upperPanel, SWT.NONE); lowerSashForm.setOrientation(SWT.HORIZONTAL); lowerSashForm.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); domTreeComp = new DomTreeComposite(lowerSashForm, SWT.None, this); createWebViewer(); lowerSashForm.setWeights(new int[] { 20, 80 }); //lowerSashForm.setSashWidth(3); } /** * This method initializes webViewer * @throws MaxCvsExceededException * @throws KeyExpiredException * */ private void createWebViewer() throws MaxCvsExceededException, KeyExpiredException { // Retrieve Basic credentials of connector String user = htmlConnector.getAuthUser(); String password = htmlConnector.getAuthPassword(); user = user.equals("") ? null : user; IWebViewerStudio webViewer = new XulWebViewerImpl(htmlConnector.context, lowerSashForm, SWT.NONE); tabManager = webViewer.getTabManager(); tabManager.addChangeListener(new SelectionChangedListener() { public void changed() { documentCompletedListener.completed(); } }); webViewer.setLayoutData(new GridData(SWT.FILL, SWT.FILL, true, true)); webViewer.setCredentials(user, password); ConvertigoPlugin.logDebug2( "(HtmlConnectorDesignComposite) Connector credentials has been set: " + user + ",******"); // Set webViewer as viewer for connector html parser htmlConnector.getHtmlParser().setWebViewer(webViewer); webViewer.setUrl(htmlConnector.getBaseUrl()); webViewer.addSelectionChangedListener(selectionChangedListener); webViewer.addDocumentCompletedListener(documentCompletedListener); } public HtmlScreenClass getParentHtmlScreenClass() throws EngineException { HtmlScreenClass parentObject = null; // Case of Learning mode if (htmlConnector.isLearning()) { // In case of ScreenClass was deleted if ((detectedScreenClass != null) && (detectedScreenClass.getParent() == null)) { detectedScreenClass = null; } // Set parent ScreenClass to last detected ScreenClass parentObject = detectedScreenClass; } if (parentObject == null) { // Set parent ScreenClass to current selected ScreenClass Object object = projectExplorerView.getFirstSelectedDatabaseObject(); if (object != null && object instanceof HtmlScreenClass) { parentObject = (HtmlScreenClass) object; if (!parentObject.getProject().equals(htmlConnector.getProject())) { parentObject = null; } } // Set parent ScreenClass to current ScreenClass if (parentObject == null) { parentObject = htmlConnector.getCurrentScreenClass(); } } return parentObject; } public StatementWithExpressions getParentStatement() { StatementWithExpressions parentObject = null; // TODO Case of Learning mode // if (htmlConnector.isLearning()) { // // parent transaction is the learning transaction // parentObject = (HtmlTransaction)htmlConnector.getLearningTransaction(); // } // Set parent statement to current selected StatementWithExpressions in properties view Object object = projectExplorerView.getFirstSelectedDatabaseObject(); if (object != null && object instanceof StatementWithExpressions) { parentObject = (StatementWithExpressions) object; if (!parentObject.getProject().equals(htmlConnector.getProject())) { parentObject = null; } } return parentObject; } private void showCurrentScreenClass() { Thread th = new Thread(new Runnable() { public void run() { final Document currentWebDom = getWebViewer().getDom(); if (currentWebDom == null) { ConvertigoPlugin.errorMessageBox("Mozilla retrieved Dom is null!"); return; } //Engine.logBeans.debug3("(HtmlConnectorDesignComposite) showCurrentScreenClass dom:\n"+ XMLUtils.prettyPrintDOM(currentWebDom), null); ScreenClass htmlScreenClass = null; synchronized (htmlConnector) { Document currentDom = htmlConnector.getCurrentXmlDocument(); htmlConnector.setCurrentXmlDocument(currentWebDom); try { htmlScreenClass = htmlConnector.getCurrentScreenClass(); } catch (EngineException e) { ConvertigoPlugin.logInfo("Engine exception occurs: " + e.getMessage()); } htmlConnector.setCurrentXmlDocument(currentDom); } fireObjectSelected(new CompositeEvent(htmlScreenClass)); } }); th.setName("Document completed Update"); th.start(); } protected void startLearn() { if (htmlConnector.isLearning()) { stopLearn(); } // add current composite view to the HTTP proxy listeners getWebViewer().addHttpProxyEventListener(this); // set learning flag htmlConnector.markAsLearning(true); HtmlTransaction htmlTransaction = (HtmlTransaction) htmlConnector.getLearningTransaction(); if (htmlTransaction == null) { Object object = projectExplorerView.getFirstSelectedDatabaseObject(); if (object != null && object instanceof HtmlTransaction) { try { htmlTransaction = (HtmlTransaction) object; htmlTransaction.markAsLearning(true); ConvertigoPlugin.logDebug2( "(HtmlConnector) learning transaction named '" + htmlTransaction.getName() + "'"); } catch (Exception e) { } } } final HtmlTransaction transaction = htmlTransaction; Thread th = new Thread(new Runnable() { public void run() { Document dom = getWebViewer().getDom(); transaction.setCurrentXmlDocument(dom); } }); th.setName("Document completed Update"); th.start(); if (!toolLearn.isEnabled()) { toolLearn.setEnabled(true); } if (!toolLearn.getSelection()) { toolLearn.setSelection(true); } } protected void stopLearn() { if (!htmlConnector.isLearning()) { return; } // remove current composite view from HTTP proxy listeners getWebViewer().removeHttpProxyEventListener(this); HtmlTransaction htmlTransaction = (HtmlTransaction) htmlConnector.getLearningTransaction(); htmlTransaction.setCurrentXmlDocument(null); // unset learning flag htmlConnector.markAsLearning(false); ConvertigoPlugin .logDebug2("(HtmlConnector) stop learning transaction named '" + htmlTransaction.getName() + "'"); try { htmlTransaction.markAsLearning(false); } catch (EngineException e) { } if (toolLearn.isEnabled()) { toolLearn.setEnabled(false); } if (toolLearn.getSelection()) { toolLearn.setSelection(false); } } public void operationChanged(String operation) { } public void modelChanged(HttpProxyEvent event) { if (!checkProxySource(event)) { return; } String requestString = event.getRequest(); String responseString = event.getResponse(); boolean https = event.isHttps(); int status = Integer.parseInt(event.getStatus()); // do not record client redirection if ((status == HttpStatus.SC_MOVED_TEMPORARILY) || (status == HttpStatus.SC_MOVED_PERMANENTLY) || (status == HttpStatus.SC_SEE_OTHER) || (status == HttpStatus.SC_TEMPORARY_REDIRECT)) { return; } /*if (requestString.indexOf(getServer()) == -1) { return; }*/ Map<String, String> headers = parseResponseString(responseString); String contentType = headers.get(HeaderName.ContentType.value().toLowerCase()); // record only text/html or null Content-Type ... if (contentType == null) { return; } if (MimeType.Html.is(contentType) && MimeType.Plain.is(contentType)) { return; } ConvertigoPlugin.logDebug2("(HtmlConnectorDesignComposite) Learning statement..."); try { String url, method, handlerName, transactionName, statementName, scHandlerName; String normalizedScreenClassName, screenClassName; HtmlTransaction htmlTransaction = null; HTTPStatement httpStatement = null; HtmlScreenClass htmlScreenClass = null; HandlerStatement handlerStatement = null; ScHandlerStatement scHandlerStatement = null; //Document dom = null; //Log log = null; int size, index1; boolean bContinue; index1 = 0; bContinue = true; normalizedScreenClassName = "Unknown"; htmlTransaction = (HtmlTransaction) htmlConnector.getLearningTransaction(); synchronized (htmlConnector) { //dom = htmlConnector.getCurrentXmlDocument(); htmlScreenClass = htmlConnector.getCurrentScreenClass(); } screenClassName = htmlScreenClass.getName(); normalizedScreenClassName = StringUtils.normalize(htmlScreenClass.getName()); ConvertigoPlugin .logDebug2("(HtmlConnectorDesignComposite) current screen class is '" + screenClassName + "'"); if (htmlTransaction != null) { transactionName = htmlTransaction.getName(); ConvertigoPlugin.logDebug2("(HtmlConnectorDesignComposite) creating new HTTPStatement"); ConvertigoPlugin.logDebug2(requestString); httpStatement = parseRequestString(requestString); httpStatement.setHttps(https); httpStatement.setPort(https ? 443 : 80); method = httpStatement.getMethod().toLowerCase(); //size = httpStatement.getVariablesDefinitionSize(); size = httpStatement.numberOfVariables(); url = httpStatement.getUrl(htmlConnector.isHttps(), htmlConnector.getServer(), htmlConnector.getPort()); while (bContinue) { statementName = method + ((index1 == 0) ? " " : " " + index1) + " (" + url + " - " + size + ")"; statementName = StringUtils.normalize(statementName); httpStatement.setName(statementName); httpStatement.hasChanged = true; httpStatement.bNew = true; if (htmlScreenClass == null) { try { httpStatement.priority = 0; htmlTransaction.addStatement(httpStatement); ConvertigoPlugin.logDebug2( "(HtmlConnectorDesignComposite) added new HTTPStatement to default transaction '" + transactionName + "'"); fireObjectChanged(new CompositeEvent(htmlTransaction)); Engine.theApp.fireObjectDetected(new EngineEvent(httpStatement)); bContinue = false; } catch (ObjectWithSameNameException owsne) { index1++; } } else { if (htmlConnector.isAccumulating()) handlerName = "on" + normalizedScreenClassName + "Exit"; else handlerName = "on" + normalizedScreenClassName + "Entry"; handlerStatement = htmlTransaction.getHandlerStatement(handlerName); if (handlerStatement != null) { try { handlerStatement.addStatement(httpStatement); ConvertigoPlugin.logDebug2( "(HtmlConnectorDesignComposite) added new HTTPStatement to handler '" + handlerName + "' of transaction '" + transactionName + "'"); fireObjectChanged(new CompositeEvent(handlerStatement)); Engine.theApp.fireObjectDetected(new EngineEvent(httpStatement)); bContinue = false; } catch (ObjectWithSameNameException owsne) { index1++; } } else { try { if (htmlConnector.isAccumulating()) scHandlerStatement = new ScExitHandlerStatement(normalizedScreenClassName); else scHandlerStatement = new ScEntryHandlerStatement(normalizedScreenClassName); scHandlerName = scHandlerStatement.getName(); scHandlerStatement.setName(scHandlerName); scHandlerStatement.hasChanged = true; scHandlerStatement.bNew = true; scHandlerStatement.priority = 0; htmlTransaction.addStatement(scHandlerStatement); ConvertigoPlugin.logDebug2( "(HtmlConnectorDesignComposite) added new ScExitHandlerStatement '" + handlerName + "' of transaction '" + transactionName + "'"); try { scHandlerStatement.addStatement(httpStatement); ConvertigoPlugin .logDebug2("(HtmlConnectorDesignComposite) added new HTTPStatement '" + statementName + "' to ScExitHandlerStatement '" + handlerName + "'"); fireObjectChanged(new CompositeEvent(htmlTransaction)); Engine.theApp.fireObjectDetected(new EngineEvent(httpStatement)); bContinue = false; } catch (ObjectWithSameNameException owsne) { index1++; } } // Should not append catch (ObjectWithSameNameException owsne) { throw new EngineException(owsne.getMessage()); } } } } } else { throw new EngineException("Found none learning transaction"); } } catch (EngineException e) { ConvertigoPlugin.logException(e, "An exception occured while learning"); } } public HTTPStatement parseRequestString(String requestString) { String httpHeader, httpValue; String method, uri, version, host; String line, token, data; int index, i = 0; HTTPStatement httpStatement = new HTTPStatement(); try { StringTokenizer st = new StringTokenizer(requestString, "\r"); while (st.hasMoreTokens()) { line = st.nextToken(); //line is not empty if (line.trim().length() > 0) { //this is an header ==> <headername>:<space><headervalue> if ((index = line.indexOf(":")) != -1) { httpHeader = line.substring(1, index).toLowerCase(); // skip the first space httpValue = line.substring(index + 2).toLowerCase(); // skip the space after ':' if (httpHeader.equalsIgnoreCase("host")) { host = httpValue; httpStatement.setHost(host); } else if (HeaderName.Accept.is(httpHeader) && !HeaderName.AcceptEncoding.is(httpHeader) || HeaderName.Referer.is(httpHeader) || HeaderName.ContentType.is(httpHeader)) { ;// keep this header } else { httpHeader = HttpConnector.DYNAMIC_HEADER_PREFIX + httpHeader;// skip this header } httpStatement.addHeader(httpHeader, httpValue); } else { // this is the request-line with HTTP verb StringTokenizer stk = new StringTokenizer(line, " "); while (stk.hasMoreTokens()) { token = stk.nextToken(); if (i == 0) { method = token; httpStatement.setMethod(method); } if (i == 1) { uri = token; if ((index = uri.indexOf("?")) != -1) { data = uri.substring(index + 1); uri = uri.substring(0, index); parseHttpData(httpStatement, data, "GET"); } // set uri as constant string httpStatement.setRequestUri("\"" + uri + "\""); } if (i == 2) { version = token; httpStatement.setHttpVersion(version); } i++; } } } else { // there was an empty line ==> Next token is DATA line = st.nextToken(); parseHttpData(httpStatement, line, "POST"); break; } } } catch (Exception e) { ; } return httpStatement; } private void parseHttpData(HTTPStatement httpStatement, String line, String method) { line = TextCodec.UTF8inURLDecode(line); //decode url variables StringTokenizer stData = new StringTokenizer(line, "&"); String left, right, name, value, dataName; Object ob, dataValue; Map<String, Object> names; boolean bMulti; List<String> v; v = null; names = new HashMap<String, Object>(); while (stData.hasMoreTokens()) { String dataElement = stData.nextToken(); if (dataElement.indexOf('=') != -1) { left = dataElement.substring(0, dataElement.indexOf('=')); right = (dataElement.indexOf('=') < dataElement.length() ? dataElement.substring(dataElement.indexOf('=') + 1) : ""); name = left.trim(); value = right.trim(); if (names.containsKey(name)) { ob = names.get(name); if (ob instanceof String) { v = new ArrayList<String>(); v.add((String) ob); } else if (ob instanceof List) { v = GenericUtils.cast(ob); } if (v != null) { v.add(value); names.put(name, v); } } else { names.put(name, value); } } } for (Enumeration<String> e = Collections.enumeration(names.keySet()); e.hasMoreElements();) { dataName = e.nextElement(); dataValue = names.get(dataName); bMulti = dataValue instanceof List; httpStatement.addData(dataName, dataValue, bMulti, method); } } public Map<String, String> parseResponseString(String responseString) { Map<String, String> htHeaders = new HashMap<String, String>(); String httpHeader, httpValue; String line; int index, i = 0; try { StringTokenizer st = new StringTokenizer(responseString, "\r"); while (st.hasMoreTokens()) { line = st.nextToken(); //line is not empty if (line.trim().length() > 0) { //this is an header ==> <headername>:<space><headervalue> if ((index = line.indexOf(":")) != -1) { httpHeader = line.substring(1, index).toLowerCase(); // skip the first space httpValue = line.substring(index + 2).toLowerCase(); // skip the space after ':' htHeaders.put(httpHeader, httpValue); } else { // this is the status-line StringTokenizer stk = new StringTokenizer(line, " "); while (stk.hasMoreTokens()) { //token = stk.nextToken(); if (i == 0) ;//version = token; if (i == 1) ;//status = token; if (i == 2) ;//reason = token; i++; } } } else { // there was an empty line ==> Next token is DATA line = st.nextToken(); break; } } } catch (Exception e) { ; } return htHeaders; } public void selectionChanged(SelectionChangedEvent event) { if (event.getSource() instanceof ISelectionProvider) { IStructuredSelection selection = (IStructuredSelection) event.getSelection(); TreeObject treeObject = (TreeObject) selection.getFirstElement(); if (treeObject != null) { ConnectorTreeObject connectorTreeObject = treeObject.getConnectorTreeObject(); if (connectorTreeObject != null) { Connector connector = (Connector) connectorTreeObject.getObject(); if (connector.equals(htmlConnector)) { if (treeObject instanceof TransactionTreeObject) { if (!htmlConnector.isLearning()) toolLearn.setEnabled(true); } else { if (!htmlConnector.isLearning()) toolLearn.setEnabled(false); } } else { if (!htmlConnector.isLearning()) toolLearn.setEnabled(false); } } } } } private boolean checkEventSource(EventObject event) { boolean isSourceFromConnector = false; Object source = event.getSource(); if (event instanceof EngineEvent) { if (source instanceof DatabaseObject) { Connector connector = ((DatabaseObject) source).getConnector(); if ((connector != null) && (connector.equals(htmlConnector))) isSourceFromConnector = true; } } return isSourceFromConnector; } private boolean checkProxySource(HttpProxyEvent event) { boolean isSourceFromConnector = false; String contextID = event.getContextID(); if (contextID == null) ConvertigoPlugin .errorMessageBox("Missing contextID in HttpProxyEvent.\nPlease update convertigo HttpProxy."); if (contextID.equals(htmlConnector.context.contextID)) { isSourceFromConnector = true; } return isSourceFromConnector; } public void blocksChanged(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } public void documentGenerated(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } public void objectDetected(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } public void stepReached(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } public void transactionStarted(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; runningTransaction = (HtmlTransaction) engineEvent.getSource(); getDisplay().asyncExec(new Runnable() { public void run() { //TODO:treeToolBar.setEnabled(false); objectToolBar.setEnabled(false); learnToolBar.setEnabled(false); toolStopTransaction.setEnabled(true); } }); } public void transactionFinished(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; if (runningTransaction.equals(xmlizingTransaction)) xmlizingTransaction = null; runningTransaction = null; getDisplay().asyncExec(new Runnable() { public void run() { //TODO:treeToolBar.setEnabled(true); objectToolBar.setEnabled(true); learnToolBar.setEnabled(true); toolStopTransaction.setEnabled(false); } }); } public void clearEditor(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } public void sequenceFinished(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } public void sequenceStarted(EngineEvent engineEvent) { if (!checkEventSource(engineEvent)) return; } private void generateXml() { Thread th = new Thread(new Runnable() { public void run() { final Document dom = getWebViewer().getDom(); if (dom == null) { ConvertigoPlugin.errorMessageBox("Mozilla retrieved Dom is null!"); return; } //Engine.logBeans.debug3("(HtmlConnectorDesignComposite) xmlizing dom:\n"+ XMLUtils.prettyPrintDOM(dom), null); // synchronized (htmlConnector) { Document currentDom = htmlConnector.getCurrentXmlDocument(); // Report from 4.5: fix #401 HtmlTransaction htmlTransaction = null; try { htmlTransaction = (HtmlTransaction) htmlConnector.getDefaultTransaction(); } catch (Exception e1) { } if (htmlTransaction != null) { boolean isStateFull = htmlTransaction.isStateFull(); xmlizingTransaction = htmlTransaction; xmlizingTransaction.setCurrentXmlDocument(dom); xmlizingTransaction.setStateFull(true); getDisplay().asyncExec(new Runnable() { public void run() { ConnectorEditor connectorEditor = ConvertigoPlugin.getDefault() .getConnectorEditor(htmlConnector); if (connectorEditor == null) transactionFinished(new EngineEvent(xmlizingTransaction)); else connectorEditor.getDocument(xmlizingTransaction.getName(), false); } }); while (xmlizingTransaction != null) { try { Thread.sleep(1000); } catch (InterruptedException e) { } } htmlTransaction.setCurrentXmlDocument(currentDom); htmlTransaction.setStateFull(isStateFull); } // } } }); th.setName("Document completed Update"); th.start(); } public IWebViewerStudio getWebViewer() { return (IWebViewerStudio) tabManager.getCurrent(); } public XpathEvaluatorComposite getXpathEvaluator() { return xpathEvaluator; } public DomTreeComposite getDomTreeComp() { return domTreeComp; } public void createScreenClassFromSelection() throws EngineException { String className = "com.twinsoft.convertigo.beans.core.ScreenClass"; // Retrieve selected criteria xpath String criteriaXpath = xpathEvaluator.getSelectionXpath(); // Retrieve parent ScreenClass HtmlScreenClass parentObject = getParentHtmlScreenClass(); NewObjectWizard newObjectWizard = new NewObjectWizard(parentObject, className); WizardDialog wzdlg = new WizardDialog(Display.getCurrent().getActiveShell(), newObjectWizard); wzdlg.setPageSize(850, 650); wzdlg.open(); if (wzdlg.getReturnCode() != Window.CANCEL) { HtmlScreenClass htmlScreenClass = (HtmlScreenClass) newObjectWizard.newBean; if (htmlScreenClass != null) { String screenClassName = htmlScreenClass.getName(); // Add criteria to screen class createCriteria(htmlScreenClass, criteriaXpath); // Set detected ScreenClass to newly created one if (htmlConnector.isLearning()) { detectedScreenClass = htmlScreenClass; ConvertigoPlugin.logDebug2( "(HtmlConnectorDesignComposite) Detected screen class is set to newly created one named '" + screenClassName + "'"); } else { ConvertigoPlugin.logDebug2("(HtmlConnectorDesignComposite) New screen class named '" + screenClassName + "' has been added"); } // Reload parent ScreenClass in Tree fireObjectChanged(new CompositeEvent(parentObject)); // Set selection on newly created screenclass fireObjectSelected(new CompositeEvent(htmlScreenClass)); // Highlight new detected ScreenClass in Tree if (htmlConnector.isLearning()) Engine.theApp.fireObjectDetected(new EngineEvent(htmlScreenClass)); //TODO:toolScreenclass.setEnabled(false); } } } public void createCriteriasFromSelection(Document dom) throws EngineException { String className = "com.twinsoft.convertigo.beans.core.Criteria"; // Retrieve selected criterias xpath String criteriaXpath = xpathEvaluator.getSelectionXpath(); // Retrieve parent ScreenClass HtmlScreenClass parentObject = getParentHtmlScreenClass(); NewObjectWizard newObjectWizard = new NewObjectWizard(parentObject, className, criteriaXpath, dom); WizardDialog wzdlg = new WizardDialog(Display.getCurrent().getActiveShell(), newObjectWizard); wzdlg.setPageSize(850, 650); wzdlg.open(); if (wzdlg.getReturnCode() != Window.CANCEL) { Criteria criteria = (Criteria) newObjectWizard.newBean; // Reload parent ScreenClass in Tree fireObjectChanged(new CompositeEvent(parentObject)); // Set selection on last created criteria (will expand tree to new criteria) if (criteria != null) fireObjectSelected(new CompositeEvent(criteria)); // Set back selection on parent ScreenClass fireObjectSelected(new CompositeEvent(parentObject)); } } private XPath createCriteria(HtmlScreenClass parentObject, String criteriaXpath) { XPath criteria = null; try { criteria = new XPath(); criteria.setXpath(criteriaXpath); criteria.hasChanged = true; criteria.bNew = true; parentObject.addCriteria(criteria); ConvertigoPlugin.logInfo("New criteria named '" + criteria.getName() + "' has been added to '" + parentObject.getName() + "' screenclass"); } catch (EngineException e) { String message = "Unable to create new criteria!"; ConvertigoPlugin.logException(e, message); } return criteria; } public void createExtractionRuleFromSelection(Document dom) throws EngineException { String className = "com.twinsoft.convertigo.beans.core.ExtractionRule"; // Retrieve selected extraction rule xpath String extractionrulesXpath = xpathEvaluator.getSelectionXpath(); // Retrieve parent ScreenClass HtmlScreenClass parentObject = getParentHtmlScreenClass(); // Add extraction rule to screen class NewObjectWizard newObjectWizard = new NewObjectWizard(parentObject, className, extractionrulesXpath, dom); WizardDialog wzdlg = new WizardDialog(Display.getCurrent().getActiveShell(), newObjectWizard); wzdlg.setPageSize(850, 650); wzdlg.open(); if (wzdlg.getReturnCode() != Window.CANCEL) { HtmlExtractionRule extractionrule = (HtmlExtractionRule) newObjectWizard.newBean; // Reload parent ScreenClass in Tree fireObjectChanged(new CompositeEvent(parentObject)); // Set selection on new extraction rule (will expand tree to new extraction rule) if (extractionrule != null) fireObjectSelected(new CompositeEvent(extractionrule)); // Set back selection on parent ScreenClass fireObjectSelected(new CompositeEvent(parentObject)); } } public void createStatementFromSelection() { String className = "com.twinsoft.convertigo.beans.core.Statement"; // Retrieve selected statement xpath String statementXpath = xpathEvaluator.getSelectionXpath(); // Retrieve parent Statement Statement parentObject = getParentStatement(); if (parentObject == null) { ConvertigoPlugin.errorMessageBox( "Unable to create a new statement.\nThe selected handler belongs to a different HTML connector."); return; } // Add statement to parent statement NewObjectWizard newObjectWizard = new NewObjectWizard(parentObject, className, statementXpath, null); WizardDialog wzdlg = new WizardDialog(Display.getCurrent().getActiveShell(), newObjectWizard); wzdlg.setPageSize(850, 650); wzdlg.open(); if (wzdlg.getReturnCode() != Window.CANCEL) { Statement statement = (Statement) newObjectWizard.newBean; // Reload parent statement in Tree fireObjectChanged(new CompositeEvent(parentObject)); // Set selection on new statement (will expand tree to new statement) if (statement != null) fireObjectSelected(new CompositeEvent(statement)); // Set back selection on parent statement fireObjectSelected(new CompositeEvent(parentObject)); } } public void createStatementFromGenerator(Document dom) { // Retrieve selected statement generator xpath String statementGeneratorXpath = xpathEvaluator.getSelectionXpath(); // retrieve element on which generate a statement // every test has been done before activating the button, no need to do them again Element element = (Element) (dom.getDocumentElement().getChildNodes().item(0)); boolean clickable = false, valuable = false, checkable = false, selectable = false, radioable = false, formable = false; if (element.getTagName().equalsIgnoreCase("A")) { clickable = true; } else if (element.getTagName().equalsIgnoreCase("INPUT")) { String type = element.getAttribute("type"); clickable = Arrays.binarySearch(new String[] { "button", "checkbox", "radio", "submit" }, type) > -1; //warning, must be sort valuable = Arrays.binarySearch(new String[] { "", "password", "text" }, type) > -1; //warning, must be sort checkable = Arrays.binarySearch(new String[] { "checkbox", "radio" }, type) > -1; //warning, must be sort radioable = type.equals("radio"); } else if (element.getTagName().equalsIgnoreCase("TEXTAREA")) { valuable = true; } else if (element.getTagName().equalsIgnoreCase("SELECT")) { selectable = true; } else if (element.getTagName().equalsIgnoreCase("FORM")) { formable = true; } // Retrieve parent Statement StatementWithExpressions parentObject = getParentStatement(); // launch wizard StatementGeneratorWizard statementGeneratorWizard = new StatementGeneratorWizard(parentObject, statementGeneratorXpath, new boolean[] { clickable, valuable, checkable, selectable, radioable, formable }); WizardDialog wzdlg = new WizardDialog(Display.getCurrent().getActiveShell(), statementGeneratorWizard); wzdlg.open(); if (wzdlg.getReturnCode() != Window.CANCEL) { // TODO } } public ProjectExplorerView getProjectExplorerView() { return projectExplorerView; } public HtmlConnector getHtmlConnector() { return htmlConnector; } }