All Downloads are FREE. Search and download functionalities are using the official Maven repository.

net.sf.gluebooster.java.booster.basic.text.html.HtmlDocumentationWriter Maven / Gradle / Ivy

package net.sf.gluebooster.java.booster.basic.text.html;



import java.io.File;
import java.util.Arrays;
import java.util.Date;
import java.util.Hashtable;

import javax.activation.UnsupportedDataTypeException;
import javax.naming.Context;
import javax.naming.Name;
import javax.script.ScriptEngine;
import javax.swing.text.html.HTML;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import net.sf.gluebooster.java.booster.basic.container.BoostedNode;
import net.sf.gluebooster.java.booster.basic.events.RuntimeExceptionThrowingThrowableHandler;
import net.sf.gluebooster.java.booster.basic.events.ThrowableHandler;
import net.sf.gluebooster.java.booster.basic.meta.DocumentationContext;
import net.sf.gluebooster.java.booster.basic.resources.FileResourceSystem;
import net.sf.gluebooster.java.booster.basic.text.general.BookBoostUtils;
import net.sf.gluebooster.java.booster.basic.text.general.BookContext;
import net.sf.gluebooster.java.booster.basic.text.general.DocumentationResourcesId;
import net.sf.gluebooster.java.booster.essentials.container.ResourceSystem;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.Callable;
import net.sf.gluebooster.java.booster.essentials.eventsCommands.CallableAbstraction;
import net.sf.gluebooster.java.booster.essentials.meta.objects.IoDescription;
import net.sf.gluebooster.java.booster.essentials.utils.Check;
import net.sf.gluebooster.java.booster.essentials.utils.Constants;
import net.sf.gluebooster.java.booster.essentials.utils.ContainerBoostUtils;
import net.sf.gluebooster.java.booster.essentials.utils.DomBoostUtils;
import net.sf.gluebooster.java.booster.essentials.utils.GuiBoostUtils;
import net.sf.gluebooster.java.booster.essentials.utils.IoBoostUtils;
import net.sf.gluebooster.java.booster.essentials.utils.TextBoostUtils;
import net.sf.gluebooster.java.booster.essentials.utils.ThreadBoostUtils;

/**
 * Writes a documentation as html.
 * 
 * @defaultParamText documentationNode the root node of the documentation
 * 
 * @author CBauer
 * 
 */
public class HtmlDocumentationWriter extends CallableAbstraction {


	/**
	 * The handler of warnings.
	 */
	private ThrowableHandler warningHandler = new RuntimeExceptionThrowingThrowableHandler();

	/**
	 * The default context of the documentation.
	 */
	private IoDescription output;

	/**
	 * Transforms text that is no plain string into html.
	 * 
	 */
	private Callable textTransformer = null;

	/**
	 * May add something to the html head. Call parameters are document, html head element
	 */
	private Callable htmlHeadAppender = null;

	/**
	 * Adds text as nodes. The call arguments are Document, Element, text
	 */
	private Callable textNodeBuilder = null;
 

	public HtmlDocumentationWriter() {
	}

	public HtmlDocumentationWriter(IoDescription output) {
		this.output = output;
	}

	/**
	 * Writes the html of a documentationNode and its children.
	 * 
	 * @param outputDirectory
	 *            the directory of the created html
	 * @return the (main) file with the html
	 */
	public IoDescription write(BoostedNode documentationNode, File outputDirectory) throws Exception {
		return write(documentationNode, new IoDescription(new FileResourceSystem(), outputDirectory));
	}

	/**
	 * Writes the html of a documentationNode and its children
	 * 
	 * @param documentationNode
	 *            the node to write
	 * @param outputDirectory
	 *            the directory of the created html
	 * @return the (main) file with the html
	 * @throws Exception
	 */
	@SuppressWarnings("unchecked")
	public IoDescription write(BoostedNode documentationNode, IoDescription outputDirectory) throws Exception {
		getLog().debug("write html");
		Object type = documentationNode.getAttributes().getType();
		

		if (BookBoostUtils.BOOK.equals(type)) {
			Document doc = DomBoostUtils.createDefaultDocumentBuilder().newDocument();
			// Pair newDir = new ImmutablePair(outputDirectory.getLeft(),
			// new File(outputDirectory.getRight(), documentationNode.getAttributes().getName().toString()));
			fillBook(doc, documentationNode, outputDirectory);
			IoDescription out = outputDirectory.getOutputStream("index.html");
			DomBoostUtils.write(doc, out.getOutputStream(), true);
			out.getOutputStream().close();
			return out;

		} else if (BookBoostUtils.SLIPCASE.equals(type) || BookBoostUtils.BOOKSHELF.equals(type)) {
			getLog().debug("writig " + type);

			// write the list of books or slipcases
			Document doc = DomBoostUtils.createDefaultDocumentBuilder().newDocument();
			Element body = createHtml(doc, documentationNode.getAttributes().getName(), HTML.Tag.BODY);
			Element list = DomBoostUtils.appendElement(doc, body, HTML.Tag.UL);
			for (BoostedNode zoomInFocusPoint: documentationNode.getAllZoomInFocus()){
				BoostedNode zoomInNode = documentationNode.getZoomIn(zoomInFocusPoint, null);
				Object subtype = zoomInNode.getAttributes().getType();
				
				if (BookBoostUtils.BOOK.equals(subtype) || BookBoostUtils.BOOKSHELF.equals(subtype) || BookBoostUtils.SLIPCASE.equals(subtype)) {
					String subdirectory = "" + zoomInNode.getAttributes().getName();
					Element li = DomBoostUtils.appendElement(doc, list, HTML.Tag.LI);
					DomBoostUtils.appendElement(
							doc,
							li,
							HTML.Tag.A,
							ContainerBoostUtils.createMap("href", subdirectory + "/index.html", "target", "content"),
							zoomInNode.getAttributes().getName());
					write(zoomInNode, outputDirectory.getChildFile(subdirectory));

				} else {
					throw new IllegalStateException("subtype not supported: " + subtype);
				}
			} 			
			IoDescription out = outputDirectory.getOutputStream("booklist.html");
			DomBoostUtils.write(doc, out.getOutputStream(), true);
			out.getOutputStream().close();

			//write the index
			doc = DomBoostUtils.createDefaultDocumentBuilder().newDocument();
			body = createHtml(doc, documentationNode.getAttributes().getName(), HTML.Tag.FRAMESET, "cols", "250,*");
			DomBoostUtils.appendElement(doc, body, HTML.Tag.FRAME, ContainerBoostUtils
					.createMap("src", "booklist.html", "name", "navigation"));
			DomBoostUtils.appendElement(doc, body, HTML.Tag.FRAME,
					ContainerBoostUtils.createMap("name", "content"));
			out = outputDirectory.getOutputStream("index.html");
			DomBoostUtils.write(doc, out.getOutputStream(), true);
			return out;
		} else {
			throw new IllegalStateException("type not supported: " + type);
			/*
			warningHandler.handleThrowable(new UnsupportedOperationException(
					"close currently not supported for type " + type));
			*/
		}

	} 
	

	/**
	 * Fill a book with the content of a document
	 * 
	 * @param doc
	 *            contains the content
	 * @param bookNode
	 *            the root node of the book
	 * @param outputDirectory
	 *            the directory of the created html
	 */
	private void fillBook(Document doc, BoostedNode bookNode, IoDescription outputDirectory) throws Exception {
		Element body = createHtml(doc, bookNode.getAttributes().getName(), HTML.Tag.BODY);
		BookContext bookContext = new BookContext();
		bookContext.setChapterBreadcrumb(new Object[]{0});//you are in the first navigation level, with 0 chapters before
		fillBookChapter(bookNode, bookContext, doc, body, false, outputDirectory);
		
	} 
	
	/**
	 * Create html from a document.
	 * 
	 * @param doc
	 *            contains the content
	 * @param bodyOrFrameset
	 *            body or frameset information
	 * @param bodyAttributes
	 *            additional attributes of the body
	 * @param title
	 *            the title of the html
	 * @return the body element
	 */
	@SuppressWarnings({ "unchecked", "unused" })
	private Element createHtml(Document doc, Object title, Object bodyOrFrameset, Object... bodyAttributes) throws Exception {
		Element html = DomBoostUtils.appendElement(doc, doc, HTML.Tag.HTML);
		Element head = DomBoostUtils.appendElement(doc, html,HTML.Tag.HEAD);
		DomBoostUtils.appendElement(doc, head, HTML.Tag.META, ContainerBoostUtils
				.createMap("name", "date", "content", new Date().toString()),
				"");
		if (htmlHeadAppender != null) {
			htmlHeadAppender.call(doc, head);
		}

		Element body = DomBoostUtils.appendElement(doc, html, bodyOrFrameset,
				ContainerBoostUtils.createMap(bodyAttributes));
		Element titleElement = DomBoostUtils.appendElement(doc, body, HTML.Tag.DIV,
				ContainerBoostUtils.createMap("style", "font-size:xx-large"),
				title);
		return body;
	}

	/**
	 * Adds default attributes of a node to an html element
	 * 
	 * @param node
	 *            the source of the attributes
	 * @param element
	 *            will be modified
	 */
	private void addDefaultAttributes(BoostedNode node, Element element) {
		Object id = node.getAttributes().getId();
		if (id != null) {
			element.setAttribute("id", id.toString());
		}

	}

	/**
	 * Fill in a chapter of the book
	 * 
	 * @param chapterNode
	 *            the root element with the content of the chapter
	 * @param bookContext
	 *            the context of the book
	 * @param doc
	 *            the document of the book
	 * @param parentElement
	 *            the parent of the chapter
	 * @param writeChapterHeadline
	 *            should a headline be written
	 * @param outputDirectory
	 *            the directory of the created html
	 * 
	 */
	private void fillBookChapter(BoostedNode chapterNode, BookContext bookContext, Document doc, Element parentElement, boolean writeChapterHeadline,
			IoDescription outputDirectory) throws Exception {
		if (writeChapterHeadline){
			int chapterLevel = bookContext.getChapterBreadcrumb().length;
			Object tag;
			//HTML has only h1 ... h6
			if (chapterLevel <7)
				tag = "h" + chapterLevel;
			else {
				tag = HTML.Tag.DIV;
			}

			// Element node = DomBoostUtils.appendElement(doc, parentElement, tag, null, chapterNode.getAttributes().getName());xxx
			Element node = DomBoostUtils.appendElement(doc, parentElement, tag);
			addDefaultAttributes(chapterNode, node);
			appendText(doc, node, chapterNode.getAttributes().getName());

		}
		
		int chapterCount = 0;
		for (BoostedNode zoomInFocusPoint: chapterNode.getAllZoomInFocus()){
			BoostedNode zoomInNode = chapterNode.getZoomIn(zoomInFocusPoint, null);
			Object type = zoomInNode.getAttributes().getType();
			
			if (DocumentationResourcesId.CHAPTER.equals(type)) {
				BookContext newBookContext = (BookContext) bookContext.clone();
				newBookContext.setChapterBreadcrumb(Arrays.copyOf(newBookContext.getChapterBreadcrumb(), newBookContext.getChapterBreadcrumb().length + 1) );
				newBookContext.getChapterBreadcrumb()[bookContext.getChapterBreadcrumb().length] = chapterCount++;
				fillBookChapter(zoomInNode, newBookContext, doc, parentElement, true, outputDirectory);
			}else if (HTML.Tag.DIV.equals(type)){
				 Element div = DomBoostUtils.appendElement(doc, parentElement, HTML.Tag.DIV);
				Object[] meta = BookBoostUtils.getMeta(zoomInNode);
				if (meta != null) {
					for (Object metaPart : meta) {
						// currently all meta data is written as subtag (reasonable for STRONG, EM, ...)
						div = DomBoostUtils.appendElement(doc, div, metaPart);
					}
				}

				 fillBookChapter(zoomInNode, bookContext, doc, div, false, outputDirectory);
			} else if (TextBoostUtils.TEXT.equals(type)) {
				appendText(doc, parentElement, zoomInNode.getAttributes().getValue());
				// Object text = zoomInNode.getAttributes().getValue();
				// if (text instanceof CharSequence || textTransformer == null) {
				// DomBoostUtils.appendText(doc, parentElement, text);
				// } else {
				// DomBoostUtils.appendRaw(doc, parentElement, textTransformer.call(text));
				// }

			} else if (Constants.RAW.is(type)) {
				DomBoostUtils.appendRaw(doc, parentElement, zoomInNode.getAttributes().getValue());
			}else if (GuiBoostUtils.TYPE_IMAGE.equals(type)){

				String filename = (String) zoomInNode.getAttributes().getAttribute(ScriptEngine.FILENAME);
				if (filename == null) {
					ThreadBoostUtils.sleep(2);// to get a new time
					filename = "images/file"
							+ System.currentTimeMillis()
							+ "."
							+ zoomInNode.getAttributes().getAttribute(Constants.FORMAT);
					zoomInNode.getAttributes().setAttribute(
							ScriptEngine.FILENAME, filename);
				}

				Element img = DomBoostUtils.appendElement(doc, parentElement,
						HTML.Tag.IMG, ContainerBoostUtils.createMap(
								HTML.Attribute.SRC, filename));

				// the image must be stored in the same directory as the html
				IoDescription out = outputDirectory.getOutputStream(filename);
				out.getOutputStream().write((byte[]) zoomInNode.getAttributes().getValue());
				out.getOutputStream().close();

				
			}else {
				warningHandler.handleThrowable(new UnsupportedDataTypeException("type " + type ));
			}
			

		}
		
		  
	}

	/**
	 * Appends text to a node.
	 * 
	 * @param doc
	 *            the html document of the node
	 * @param parentElement
	 *            the node
	 * @param text
	 *            may be a charsequence or be composed of parts (transformed by the textTransformer)
	 */
	private void appendText(Document doc, Element parentElement, Object text) throws Exception {
		if (text instanceof CharSequence || (textTransformer == null && textNodeBuilder == null)) {
			DomBoostUtils.appendText(doc, parentElement, text);
		} else {
			if (textTransformer != null) {
				DomBoostUtils.appendRaw(doc, parentElement, textTransformer.call(text));
			} else if (textNodeBuilder != null) {
				textNodeBuilder.call(doc, parentElement, text);
			} else {
				throw new IllegalStateException("no text transformation possible");
			}
		}

	}

	public ThrowableHandler getWarningHandler() {
		return warningHandler;
	}

	public void setWarningHandler(
			ThrowableHandler warningHandler) {
		this.warningHandler = warningHandler;
	}


	/**
	 * Creates html from a BoostedNode Structure. TODO the documentation of the environment keys must be put somewhere more abstract.
	 * 
	 * @param boostedNode
	 *            the root of the document
	 * @param environment
	 *            Keys: File.class the target directory of the html; ResourceSystem.class the system which will write the file
	 * @return The file of the index.html
	 * @throws Exception
	 */
	private IoDescription createHtml(Object boostedNode, Hashtable environment) throws Exception {
		ResourceSystem filesystem = Check.notNullWithDefault((environment == null) ? null : environment.get(ResourceSystem.class), "resource system",
				(output == null) ? null : output.getResourceSystem(), new FileResourceSystem());
		File directory = IoBoostUtils.getFile(Check.notNullWithDefault((environment == null) ? null : environment.get(File.class), "Target directory file",
				(environment == null) ? null : environment.get(DocumentationContext.DOCUMENTATION_TARGET_PARAMETER),
				(output == null) ? null : output.getFile()));
		BoostedNode document = Check.notNull(boostedNode, "BoostedNode containing the document root");
		return write(document, new IoDescription(filesystem, directory));

	}

	// @Override
	// public Object getObjectInstance(Object boostedNode, Name name, Context nameCtx, Hashtable environment) throws Exception {
	// return createHtml(boostedNode, environment);
	// // ResourceSystem filesystem = Check.notNullWithDefault((environment == null) ? null : environment.get(ResourceSystem.class), "resource system",
	// // (output == null) ? null : output.getResourceSystem(), new FileResourceSystem());
	// // File directory = IoBoostUtils.getFile(Check.notNullWithDefault((environment == null) ? null : environment.get(File.class), "Target directory file",
	// // (environment == null) ? null : environment.get(DocumentationContext.DOCUMENTATION_TARGET_PARAMETER),
	// // (output == null) ? null : output.getFile()));
	// // BoostedNode document = Check.notNull(boostedNode, "BoostedNode containing the document root");
	// // return write(document, new IoDescription(filesystem, directory));
	//
	// }

	public IoDescription getOutput() {
		return output;
	}

	public void setOutput(IoDescription output) {
		this.output = output;
	}

	public Callable getTextTransformer() {
		return textTransformer;
	}

	public void setTextTransformer(Callable textTransformer) {
		this.textTransformer = textTransformer;
	}

	public Callable getTextNodeBuilder() {
		return textNodeBuilder;
	}

	public void setTextNodeBuilder(Callable textNodeBuilder) {
		this.textNodeBuilder = textNodeBuilder;
	}

	public Callable getHtmlHeadAppender() {
		return htmlHeadAppender;
	}

	public void setHtmlHeadAppender(Callable htmlHeadAppender) {
		this.htmlHeadAppender = htmlHeadAppender;
	}

	@Override
	protected IoDescription callImpl(Object... parameters) throws Exception {
		Object boostedNode = parameters[0];
		Hashtable environment = (Hashtable) parameters[1];
		return createHtml(boostedNode, environment);
		// return (IoDescription) getObjectInstance(boostedNode, null, null, environment);
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy