org.client.JavaApp2Workbook.java Source code

Java tutorial

Introduction

Here is the source code for org.client.JavaApp2Workbook.java

Source

/* Xholon Runtime Framework - executes event-driven & dynamic applications
 * Copyright (C) 2014 Ken Webb
 *
 * This library is free software; you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License
 * as published by the Free Software Foundation; either version 2.1
 * of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307  USA
 */

package org.client;

import com.google.gwt.http.client.RequestBuilder;
import com.google.gwt.http.client.RequestCallback;
import com.google.gwt.http.client.RequestException;
import com.google.gwt.http.client.Request;
import com.google.gwt.http.client.Response;
import com.google.gwt.http.client.URL;
import com.google.gwt.resources.client.ClientBundleWithLookup;
import com.google.gwt.storage.client.Storage;
import com.google.gwt.user.client.Window;
import com.google.gwt.user.client.Window.Location;

import java.util.Date;

import org.primordion.xholon.app.IApplication;
import org.primordion.xholon.base.IXholon;
import org.primordion.xholon.base.Xholon;
import org.primordion.xholon.exception.XholonConfigurationException;

/**
 * Convert an existing Xholon Java-based app into a Xholon Workbook,
 * and optionally load the Workbook into the HTML5 workbook editor.
 * It saves the workbook to the browser's localStorage.
 * It attempts to convert everything except the Java (.java) code.
 * This class is invoked by org.client.Xholon when "gui=edit".
 * @author <a href="mailto:ken@primordion.com">Ken Webb</a>
 * @see <a href="http://www.primordion.com/Xholon">Xholon Project website</a>
 * @since 0.9.1 (Created on March 18, 2014)
 */
public class JavaApp2Workbook extends Xholon {

    /**
     * For each type of thing that might be in a Xholon app,
     * there's a String to capture that thing's content,
     * and there's a boolean to record whether that thing's existence has been resolved.
     * Once all resolvable things have been resolved,
     * then the workbook can be saved and otherwise processed.
     */

    protected String _xhnStr = null;
    protected boolean _xhnResolved = false;

    protected String ihStr = null;
    protected boolean ihResolved = false;

    protected String cdStr = null;
    protected boolean cdResolved = false;

    protected String cshStr = null;
    protected boolean cshResolved = false;

    protected String infoStr = null;
    protected boolean infoResolved = false;

    protected String svgStr = null;
    protected boolean svgResolved = false;

    protected int numResolvable = 6;
    protected int numResolved = 0;

    protected IApplication app = null;

    /**
     * "save" or "edit"
     */
    protected String mode = "save";

    protected String appName = null;

    /**
     * Window name. For use with Window.open().
     * "_self" or "_blank"
     */
    protected String winName = "_self";

    /**
     * Save the app to the browser's localStorage.
     * @param configFileName The name and path of a _xhn.xml file, or null.
     * @param app 
     */
    public void save(String configFileName, IApplication app) {
        //this.println("JavaApp2Workbook.save() starting ...");
        this.app = app;
        // have app parse the xhn config file
        try {
            app.readParameters(configFileName);
        } catch (XholonConfigurationException e) {
            //logger.error(e.getMessage(), e.getCause());
        }
        resolve(configFileName, "_xhn");
        resolve(app.getInheritanceHierarchyFile(), "ih");
        resolve(app.getClassDetailsFile(), "cd");
        resolve(app.getCompositeStructureHierarchyFile(), "csh");
        resolve(app.getInformationFile(), "info");
        resolve(getImageFile(configFileName), "svg");
    }

    /**
     * Get the name of the SVG image file.
     * @param configFileName The name and path of a _xhn.xml file, or null.
     * @return The name, or null.
     */
    protected String getImageFile(String configFileName) {
        if (configFileName == null) {
            return null;
        }
        String imageFile = app.getImageFile();
        if ("default.svg".equals(imageFile)) {
            imageFile = configFileName.substring(0, configFileName.lastIndexOf("/")) + "/" + imageFile;
        }
        return imageFile;
    }

    /**
     * Optionally save the app to the browser's localStorage, and
     * invoke the workbook editor which will read it from localStorage.
     * @param configFileName The name and path of a _xhn.xml file, or null.
     * @param app 
     */
    public void edit(String configFileName, IApplication app) {
        //this.println("JavaApp2Workbook.edit() starting ...");
        mode = "edit";
        if (editItemExists()) {
            openEditWindow();
        } else {
            save(configFileName, app);
        }
    }

    /**
     * Open a window in the browser for the XholonWorkbook editor.
     */
    protected void openEditWindow() {
        //this.println("JavaApp2Workbook.openEditWindow() starting ...");
        StringBuilder wbUrl = new StringBuilder().append(GwtEnvironment.gwtHostPageBaseURL)
                .append("wb/editwb.html?app=").append(getAppName()).append("&src=lstr")
                // "runsrc=none" tells editwb to NOT specify "src=lstr" when running the edited app,
                // which is what is expected for a Java-based app
                .append("&runsrc=none");
        //this.println(wbUrl.toString());
        // replace the current window with the XholonWorkbook editor
        Window.open(wbUrl.toString(), winName, ""); // starts with "http" or "https"
    }

    /**
     * Resolve one type of content that a Xholon app can have.
     * @param fileName A local file name, or remote uri (http), or null.
     * @param contentType One of "_xhn" "ih" "cd" "csh" etc.
     */
    protected void resolve(String fileName, String contentType) {
        //this.println("trying to resolve " + fileName + " " + contentType);
        if (fileName == null) {
            // app is probably using a ClientBundle
            String txt = app.rcConfig(contentType, (ClientBundleWithLookup) app.findGwtClientBundle());
            resolveDone(txt, contentType);
            return;
        }
        final String _contentType = contentType;
        final String _fileName = fileName;
        final IXholon _this = this;
        try {
            new RequestBuilder(RequestBuilder.GET, fileName).sendRequest("", new RequestCallback() {
                @Override
                public void onResponseReceived(Request req, Response resp) {
                    if (resp.getStatusCode() == resp.SC_OK) {
                        resolveDone(resp.getText(), _contentType);
                    } else {
                        _this.println("\nrequest: GET " + _fileName);
                        _this.println("status code:" + resp.getStatusCode());
                        _this.println("status text:" + resp.getStatusText());
                        _this.println("text:\n" + resp.getText());
                        resolveDone(null, _contentType);
                    }
                }

                @Override
                public void onError(Request req, Throwable e) {
                    _this.println("onError:" + e.getMessage());
                    resolveDone(null, _contentType);
                }
            });
        } catch (RequestException e) {
            _this.println("RequestException:" + e.getMessage());
            resolveDone(null, _contentType);
        }
    }

    /**
     * Finish resolving one type of content that a Xholon app can have.
     * @param txt The text content, or null.
     * @param contentType One of "_xhn" "ih" "cd" "csh" etc.
     */
    protected void resolveDone(String txt, String contentType) {
        //this.println("resolveDone " + contentType + "\n" + txt);
        if ("_xhn".equals(contentType)) { // params
            _xhnStr = removeXmlDeclaration(txt);
            _xhnResolved = true;
        } else if ("ih".equals(contentType)) {
            // convert <XholonClass> to <_-.XholonClass>, and </XholonClass> to </_-.XholonClass>
            ihStr = removeXmlDeclaration(txt).replaceAll("XholonClass", "_-.XholonClass");
            ihResolved = true;
        } else if ("cd".equals(contentType)) {
            cdStr = removeXmlDeclaration(txt);
            cdResolved = true;
        } else if ("csh".equals(contentType)) {
            cshStr = removeXmlDeclaration(txt);
            // TODO outer XML node name must end with "System"
            cshResolved = true;
        } else if ("info".equals(contentType)) {
            infoStr = removeXmlDeclaration(txt);
            infoResolved = true;
        } else if ("svg".equals(contentType)) {
            svgStr = removeXmlDeclaration(txt);
            svgResolved = true;
        }
        numResolved++;
        if (numResolved >= numResolvable) {
            // save the workbook to localStorage
            saveWbToLocalStorage();
            // optionally open edit window
            if ("edit".equals(mode)) {
                openEditWindow();
            }
        }
    }

    /**
     * Remove initial XML declaration lines that start with "<?xml" and end with "?>",
     * and trim start and end white space.
     * @param txt An XML string that may start with an XML declaration.
     * @return An XML string with the XML declaration removed.
     */
    protected String removeXmlDeclaration(String txt) {
        if (txt == null) {
            return null;
        }
        if (txt.startsWith("<?xml")) {
            int pos = txt.indexOf("?>");
            if ((pos != -1) && (pos < 100)) {
                return txt.substring(pos + 2).trim();
            } else {
                // badly formatted XML
                return "";
            }
        } else {
            return txt.trim();
        }
    }

    /**
     * Save XholonWorkbook to localStorage.
     */
    protected void saveWbToLocalStorage() {
        //this.println("saveWbToLocalStorage");
        String wbContent = assembleWb();
        Storage storage = Storage.getLocalStorageIfSupported();
        if (storage != null) {
            String key = getAppName();
            storage.setItem(key, wbContent);
        }
    }

    /**
     * Does the edit() item already exist ?
     * @return true or false
     */
    protected boolean editItemExists() {
        //this.println("editItemExists");
        Storage storage = Storage.getLocalStorageIfSupported();
        if (storage != null) {
            String item = storage.getItem(getAppName());
            if (item == null) {
                return false;
            } else {
                return true;
            }
        }
        return false;
    }

    /**
     * Get full path+name of the Application class,
     * and return the short portion of that.
     * ex: "org.primordion.user.app.helloworldjnlp.AppHelloWorld"
     *     returns "HelloWorld"
     */
    protected String getAppName() {
        if (appName == null) {
            appName = Location.getParameter("app");
            if (appName != null) {
                // convert "+" back to " ", etc.
                appName = URL.decodeQueryString(appName);
            }
        }
        return appName;
    }

    /**
     * Assemble a XholonWorkbook from the various parts.
     */
    protected String assembleWb() {
        StringBuilder sb = new StringBuilder().append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n").append(
                "<!--Xholon Workbook http://www.primordion.com/Xholon/gwt/ MIT License, Copyright (C) Ken Webb, ")
                .append(new Date().toString()).append("-->\n").append("<XholonWorkbook>\n\n");

        // info, Notes
        sb.append("<Notes><![CDATA[\n").append("Xholon\n").append("------\n").append("Title: ").append(getAppName())
                .append("\n").append("Description: \n").append("Url: http://www.primordion.com/Xholon/gwt/\n")
                .append("InternalName: ").append(getAppName()).append("\n").append("Keywords: \n\n")
                .append("My Notes\n").append("--------\n\n");
        if (infoStr != null) {
            sb.append(infoStr);
        }
        sb.append("]]></Notes>\n\n");

        // _xhn params
        sb.append(_xhnStr).append("\n\n");

        // ih
        sb.append(ihStr).append("\n\n");

        // cd
        sb.append(cdStr).append("\n\n");

        // csh
        sb.append(cshStr).append("\n\n");

        // svg
        sb.append("<SvgClient><Attribute_String roleName=\"svgUri\"><![CDATA[data:image/svg+xml,\n");
        if (svgStr != null) {
            sb.append(svgStr);
        }
        sb.append(
                "]]></Attribute_String><Attribute_String roleName=\"setup\">${MODELNAME_DEFAULT},${SVGURI_DEFAULT}</Attribute_String></SvgClient>\n\n");

        sb.append("</XholonWorkbook>");

        return sb.toString();
    }

    public String getWinName() {
        return winName;
    }

    public void setWinName(String winName) {
        this.winName = winName;
    }

}