package jsynoptic.base;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.net.JarURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.logging.Logger;
import simtools.ui.HTMLWriter;
/**
* @author zxpletran007
*
*/
public class HelpExtractor {
static Logger _logger = simtools.util.LogConfigurator.getLogger(HelpExtractor.class.getName());
public static final String TOC_FILE_NAME = "toc_jsynoptic.html";
public static final String ENTRY_FILE_NAME = "jsynoptic.html";
public static final String CONTENT_FIRST_PAGE_NAME = "welcome.html";
public static final String TOC_FRAME_NAME = "toc_jsynoptic";
public static final String CONTENT_FRAME_NAME = "content_jsynoptic";
/**
* The node from which help content is extracted.
*/
protected HelpNode rootHelpNode;
/**
* The repository where extracted data is copied.
*/
protected File outputDirectory;
/**
* Extract help resources and generate a HTML index of content from a given HelpNode.
* @param rootHelpNode - The node from which help content is extracted.
* @param outputDirectory - The repository where extracted data is copied.
*/
public HelpExtractor(HelpNode rootHelpNode, File outputDirectory){
this.rootHelpNode = rootHelpNode;
this.outputDirectory = outputDirectory;
if (!outputDirectory.exists()){
outputDirectory.mkdir();
}
// Get help root node children
ArrayList helpContents = new ArrayList();
for(int i=0;i<rootHelpNode.getChildrenCount();i++){
HelpNode node = ((HelpNode)rootHelpNode.getChildAt(i));
helpContents.add(node);
}
// Write toc_jsynoptic.html
try{
File indexFile = new File(outputDirectory, TOC_FILE_NAME);
FileWriter writeFile= new FileWriter(indexFile);
BufferedWriter writeBuf = new BufferedWriter(writeFile);
HTMLWriter writer = new HTMLWriter(writeBuf);
writer.writeHtmlBegin();
writer.writeBodyBegin();
writer.writeHeadBegin();
writer.writeTitle("JSynoptic Help");
writer.writeHeadEnd();
writer.writeH1("JSynoptic Help", null);
// write the help index of contents
createIndexOfContentsHTMLFiles(helpContents, writer);
writer.writeBodyEnd();
writer.writeHtmlEnd();
writeBuf.close();
writeFile.close();
_logger.fine("File "+ TOC_FILE_NAME + " successfully created at " + outputDirectory);
} catch (IOException e){
_logger.severe("Cannot write index.html content. Reason is \n" + e.getMessage());
}
// Write jsynoptic.html
try{
File entryxFile = new File(outputDirectory, ENTRY_FILE_NAME);
FileWriter writeFile= new FileWriter(entryxFile);
BufferedWriter writeBuf = new BufferedWriter(writeFile);
HTMLWriter writer = new HTMLWriter(writeBuf);
writer.writeHtmlBegin();
writer.writeHeadBegin();
writer.writeTitle("JSynoptic Help");
writer.writeHeadEnd();
writer.writeFrameSetBegin("33%,*");
writer.writeFrame(TOC_FRAME_NAME, TOC_FILE_NAME);
writer.writeFrame(CONTENT_FRAME_NAME, CONTENT_FIRST_PAGE_NAME);
writer.writeNoframesBegin();
writer.writeBodyBegin();
writer.writeP("You must use a FRAME available browser");
writer.writeBodyEnd();
writer.writeNoframesEnd();
writer.writeFrameSetEnd();
writer.writeHtmlEnd();
writeBuf.close();
writeFile.close();
_logger.fine("File "+ ENTRY_FILE_NAME + " successfully created at " + outputDirectory);
} catch (IOException e){
_logger.severe("Cannot write index.html content. Reason is \n" + e.getMessage());
}
// Extract all help resources
Set helpDirectories = getHelpDirectories(helpContents);
Iterator it = helpDirectories.iterator();
boolean extractionIsOk = true;
while(it.hasNext()){
URL repositoryURL = (URL)it.next();
try {
if ( new File(repositoryURL.getFile()).exists()){
File helpDirectory = new File(repositoryURL.getFile());
File[] files = helpDirectory.listFiles();
for (int i=0;i<files.length; i++){
if (!files[i].getName().endsWith(".class")){ // get all except .class files
extractAndCopyFileEntry(files[i]);
}
}
} else {
URLConnection uc = repositoryURL.openConnection();
if (uc instanceof JarURLConnection){
JarFile jarFile = ((JarURLConnection)uc).getJarFile();
// get all jar entries that belongs to the help repository
Set jarEntries = getJarDirectoryEntries(jarFile, ((JarURLConnection) uc).getEntryName());
// extract and copy the jar entries to output directory
Iterator it2 = jarEntries.iterator();
JarEntry jarEntry;
while(it2.hasNext()){
jarEntry = (JarEntry)it2.next();
try{
extractAndCopyJarEntry(jarFile, jarEntry);
} catch(IOException e) {
_logger.warning("Error when extracting ressource" + jarEntry+ "\n. Reason is \n" + e.getMessage());
extractionIsOk = false;
}
}
} else {
_logger.warning("Cannot extract following help resource directory" + repositoryURL);
extractionIsOk = false;
}
}
} catch (IOException e) {
_logger.warning("Cannot open URL repository. Reason is \n" + e.getMessage());
extractionIsOk = false;
}
}
if (extractionIsOk){
_logger.fine("Resource files were successfuly extracted into:" + outputDirectory);
}
}
/**
* Get not a null set of URL directories where help resources are located.
*
* Actually resources shall be located in the same directory than the HTML help file
* @param children - A list of help nodes
* @return The URL directory where resources are located
*/
private Set getHelpDirectories(ArrayList children){
Set res = new HashSet();
if (children!=null){
Iterator it = children.iterator();
while(it.hasNext()){
HelpNode node = (HelpNode)it.next();
if (node != null && node.getLink()!= null){
String htmlURLname = node.getLink().toString();
if (htmlURLname.indexOf("#")!=-1){
htmlURLname = htmlURLname.substring(0,htmlURLname.indexOf("#"));
}
String repositoryURLname = htmlURLname.substring(0,htmlURLname.lastIndexOf("/")+1);
try {
res.add(new URL(repositoryURLname));
} catch (MalformedURLException e) {
e.printStackTrace();
}
// Iterate on children
res.addAll(getHelpDirectories(node.getChildren()));
}
}
}
return res;
}
/**
* Get a set of jarEntries contained into the given jar file and that belongs to given jar repository.
* Exclude .class files
* @param jarFile
* @param repositoryURLname
* @return
*/
private Set getJarDirectoryEntries(JarFile jarFile, String jarrepositoryName){
Set res = new HashSet();
if (jarFile != null && jarrepositoryName != null){
Enumeration entries = jarFile.entries();
while (entries.hasMoreElements()){
JarEntry jarEntry = (JarEntry)entries.nextElement();
String jarEntryName = jarEntry.getName();
if (jarEntryName.startsWith(jarrepositoryName) // get all excepted .class files
&& !jarEntryName.equals(jarrepositoryName)
&& !jarEntryName.endsWith(".class")
){
res.add(jarEntry);
}
}
}
return res;
}
/**
* Generate the help index of contents from the given list of help nodes and write it into the given HTML file
* @param children
* @param writer
* @throws IOException
*/
private static void createIndexOfContentsHTMLFiles(ArrayList children, HTMLWriter writer) throws IOException{
if (children!=null && !children.isEmpty()){
writer.writeULBegin();
Iterator it = children.iterator();
while(it.hasNext()){
HelpNode node = (HelpNode)it.next();
String target= null;
String title = node.toString();
if (node.getLink()!=null) {
target = node.getLink().toString();
//relative path
target = target.substring(target.lastIndexOf("/")+1);
}
writer.writeLiBegin();
writer.writeTargetReference(target, CONTENT_FRAME_NAME, title);
writer.writeLiEnd();
createIndexOfContentsHTMLFiles(node.getChildren(), writer);
}
writer.writeULEnd();
}
}
/**
* Extract a file entry resource to output directory
* @param jarFile
* @param jarEntry
* @throws IOException
*/
private void extractAndCopyFileEntry(File fileEntry) throws IOException{
FileInputStream fis = new FileInputStream(fileEntry);
FileOutputStream fos = new FileOutputStream(new File(outputDirectory, fileEntry.getName()));
try {
byte[] buf = new byte[1024];
int i = 0;
while ((i = fis.read(buf)) != -1) {
fos.write(buf, 0, i);
}
} finally {
if (fis != null) fis.close();
if (fos != null) fos.close();
}
}
/**
* Extract a jar entry resource to output directory
* @param jarFile
* @param jarEntry
* @throws IOException
*/
private void extractAndCopyJarEntry(JarFile jarFile, JarEntry jarEntry) throws IOException{
if (jarFile != null && jarEntry != null) {
InputStream entryStream = jarFile.getInputStream(jarEntry);
try {
// Create the output file (clobbering the file if it exists).
String jarName = jarEntry.getName().substring(jarEntry.getName().lastIndexOf("/")+1,jarEntry.getName().length());
FileOutputStream file = new FileOutputStream(new File (outputDirectory, jarName));
try {
// Allocate a buffer for reading the entry data.
byte[] buffer = new byte[1024];
int bytesRead;
// Read the entry data and write it to the output file.
while ((bytesRead = entryStream.read(buffer)) != -1) {
file.write(buffer, 0, bytesRead);
}
} finally {
file.close();
}
} finally {
entryStream.close();
}
}
}
}