/** * Set the match pattern in the reader. The match pattern is used to see whether current element * can be include in the result of parsing. * * @param matchPattern the match pattern */ public void setMatch(final String matchPattern) { int index = 0; firstMatchElement = (matchPattern.indexOf(SLASH) != -1) ? matchPattern.substring(0, matchPattern.indexOf(SLASH)) : matchPattern; while (index != -1) { final int start = matchPattern.indexOf(SLASH, index); final int end = matchPattern.indexOf(SLASH, start + 1); if (start != -1 && end != -1) { lastMatchElement.add(matchPattern.substring(start + 1, end)); index = end; } else if (start != -1 && end == -1) { lastMatchElement.add(matchPattern.substring(start + 1)); index = -1; } } matchList.add(firstMatchElement); final Iterator<String> it = lastMatchElement.iterator(); final StringBuffer sb = new StringBuffer(); while (it.hasNext()) { sb.append(it.next() + STRING_BLANK); } matchList.add(sb.toString()); }
@Override public void endElement(final String uri, final String localName, final String qName) throws SAXException { if (match) { if (validHref) { indexEntries.append(LESS_THAN); indexEntries.append(SLASH); indexEntries.append(qName); indexEntries.append(GREATER_THAN); } level--; } if (lastMatchElement.contains(qName) && level == 0) { if (match) { match = false; } } if (!match) { ancestorList.remove(ancestorList.size() - 1); } if (qName.equals(firstMatchElement) && verifyIndexEntries(indexEntries) && topicPath != null) { // if the href is not valid, topicPath will be null. We don't need to set the condition // to check validHref at here. /* String origin = (String) map.get(topicPath); if (origin != null) { map.put(topicPath, origin + indexEntries.toString()); } else { map.put(topicPath, indexEntries.toString()); } indexEntries = new StringBuffer(INT_1024); */ String t = topicPath; String frag = SHARP; // Get topic id if (t.contains(SHARP)) { frag = t.indexOf(SHARP) + 1 >= t.length() ? SHARP : t.substring(t.indexOf(SHARP) + 1); // remove the "#" in topic file path t = t.substring(0, t.indexOf(SHARP)); } Map<String, String> m = map.get(t); if (m != null) { final String orig = m.get(frag); m.put(frag, StringUtils.setOrAppend(orig, indexEntries.toString(), false)); } else { m = new HashMap<String, String>(INT_16); m.put(frag, indexEntries.toString()); map.put(t, m); } // TODO Added by William on 2009-06-16 for bug:2791696 reltable bug start indexEntries = new StringBuffer(INT_1024); // TODO Added by William on 2009-06-16 for bug:2791696 reltable bug end } }
/** * Get index file name. * * @param outputFileRoot root path * @return index file name */ @Override public String getIndexFileName(final String outputFileRoot) { final File indexDir = new File(outputFileRoot).getParentFile(); setFilePath(indexDir.getAbsolutePath()); final StringBuffer indexFilename = new StringBuffer(new File(indexDir, "index.xml").getAbsolutePath()); return indexFilename.toString(); }
/** * Get up-levels relative path. * * @return path to up-level */ private String getUpdateLevels() { int current = uplevels; final StringBuffer buff = new StringBuffer(); while (current > 0) { buff.append(".." + FILE_SEPARATOR); current--; } return buff.toString(); }
/** Check whether the index entries we got is meaningful and valid */ private static boolean verifyIndexEntries(final StringBuffer str) { if (str.length() == 0) { return false; } final int start = str.indexOf(GREATER_THAN); // start from first tag's end final int end = str.lastIndexOf(LESS_THAN); // end at last tag's start final String temp = str.substring(start + 1, end); if (temp.trim().length() != 0) { return true; } return false; }
/** * Append XML content into root element * * @param hrefValue href of the topicref * @param parentResult XML content to insert into * @param tmpContent XML content to insert */ private void insertAfter(String hrefValue, StringBuffer parentResult, CharSequence tmpContent) { int insertpoint = parentResult.lastIndexOf("</"); final int end = parentResult.indexOf(">", insertpoint); if (insertpoint == -1 || end == -1) { logger.error(MessageUtils.getInstance().getMessage("DOTJ033E", hrefValue).toString()); } else { if (ELEMENT_NAME_DITA.equals(parentResult.substring(insertpoint, end).trim())) { insertpoint = parentResult.lastIndexOf("</", insertpoint - 1); } parentResult.insert(insertpoint, tmpContent); } }
@Override public void startEntity(final String name) throws SAXException { needResolveEntity = StringUtils.checkEntity(name); if (match && !needResolveEntity && validHref) { indexEntries.append(StringUtils.getEntity(name)); } }
@Override public void read(final String filename) { if (matchList.isEmpty()) { throw new IllegalStateException("matchList not initialized"); } match = false; needResolveEntity = true; inputFile = new File(filename); filePath = inputFile.getParent(); inputFile.getPath(); if (indexEntries.length() != 0) { // delete all the content in indexEntries indexEntries = new StringBuffer(INT_1024); } try { reader.setErrorHandler(new DITAOTXMLErrorHandler(filename, logger)); final InputSource source = URIResolverAdapter.convertToInputSource( DitaURIResolverFactory.getURIResolver().resolve(filename, null)); reader.parse(source); } catch (final Exception e) { logger.logException(e); } }
@Override public void characters(final char[] ch, final int start, final int length) throws SAXException { if (match && needResolveEntity && validHref) { final String temp = new String(ch, start, length); indexEntries.append(StringUtils.escapeXML(temp)); } }
@Override public void ignorableWhitespace(final char[] ch, final int start, final int length) throws SAXException { if (match && validHref) { final String temp = new String(ch, start, length); indexEntries.append(temp); } }
@Override public void processingInstruction(final String target, final String data) throws SAXException { final String pi = (data != null) ? target + STRING_BLANK + data : target; if (match && needResolveEntity && validHref) { final String temp = LESS_THAN + QUESTION + StringUtils.escapeXML(pi) + QUESTION + GREATER_THAN; indexEntries.append(temp); } }
@Override public void startElement( final String uri, final String localName, final String qName, final Attributes atts) throws SAXException { final int attsLen = atts.getLength(); final String attrScope = atts.getValue(ATTRIBUTE_NAME_SCOPE); final String attrFormat = atts.getValue(ATTRIBUTE_NAME_FORMAT); if (qName.equals(firstMatchElement)) { final String hrefValue = atts.getValue(ATTRIBUTE_NAME_HREF); if (verifyIndexEntries(indexEntries) && topicPath != null) { /* String origin = (String) map.get(topicPath); map.put(topicPath, StringUtils.setOrAppend(origin, indexEntries.toString(), false)); */ String t = topicPath; String frag = SHARP; if (t.contains(SHARP)) { frag = t.indexOf(SHARP) + 1 >= t.length() ? SHARP : t.substring(t.indexOf(SHARP) + 1); t = t.substring(0, t.indexOf(SHARP)); } Map<String, String> m = map.get(t); if (m != null) { final String orig = m.get(frag); m.put(frag, StringUtils.setOrAppend(orig, indexEntries.toString(), false)); } else { m = new HashMap<String, String>(INT_16); m.put(frag, indexEntries.toString()); map.put(t, m); } indexEntries = new StringBuffer(INT_1024); } topicPath = null; if (hrefValue != null && hrefValue.indexOf(INTERNET_LINK_MARK) == -1 && (attrScope == null || ATTR_SCOPE_VALUE_LOCAL.equalsIgnoreCase(attrScope)) && (attrFormat == null || ATTR_FORMAT_VALUE_DITA.equalsIgnoreCase(attrFormat))) { // If the href is internal dita topic file topicPath = FileUtils.resolveTopic(filePath, hrefValue); validHref = true; } else { // set up the boolean to prevent the invalid href's metadata inserted into indexEntries. topicPath = null; validHref = false; } } if (!match) { ancestorList.add(qName); if (lastMatchElement.contains(qName) && checkMatch()) { match = true; level = 0; } } if (match) { if (validHref) { indexEntries.append(LESS_THAN + qName + STRING_BLANK); for (int i = 0; i < attsLen; i++) { indexEntries.append(atts.getQName(i)); indexEntries.append(EQUAL); indexEntries.append(QUOTATION); indexEntries.append(StringUtils.escapeXML(atts.getValue(i))); indexEntries.append(QUOTATION); indexEntries.append(STRING_BLANK); } indexEntries.append(GREATER_THAN); } level++; } }
@Override public void startCDATA() throws SAXException { if (match && validHref) { indexEntries.append(CDATA_HEAD); } }
private void processFile(String currentFile) throws DITAOTException { File fileToParse; final File file = new File(currentFile); if (file.isAbsolute()) { fileToParse = file; currentFile = FileUtils.getRelativePath(rootFile, currentFile); } else { fileToParse = new File(baseInputDir, currentFile); } try { fileToParse = fileToParse.getCanonicalFile(); } catch (final IOException e1) { logger.logError(e1.toString()); } logger.logInfo("Processing " + fileToParse.getAbsolutePath()); String msg = null; final Properties params = new Properties(); params.put("%1", currentFile); if (!fileToParse.exists()) { logger.logError(MessageUtils.getMessage("DOTX008E", params).toString()); return; } try { if (FileUtils.isValidTarget(currentFile.toLowerCase())) { reader.setTranstype(transtype); reader.setCurrentDir(new File(currentFile).getParent()); reader.parse(fileToParse); } else { // edited by Alan on Date:2009-11-02 for Work Item:#1590 start // logger.logWarn("Input file name is not valid DITA file name."); final Properties prop = new Properties(); prop.put("%1", fileToParse); logger.logWarn(MessageUtils.getMessage("DOTJ053W", params).toString()); // edited by Alan on Date:2009-11-02 for Work Item:#1590 end } // don't put it into dita.list if it is invalid if (reader.isValidInput()) { processParseResult(currentFile); categorizeCurrentFile(currentFile); } else if (!currentFile.equals(inputFile)) { logger.logWarn(MessageUtils.getMessage("DOTJ021W", params).toString()); } } catch (final SAXParseException sax) { // To check whether the inner third level is DITAOTBuildException // :FATALERROR final Exception inner = sax.getException(); if (inner != null && inner instanceof DITAOTException) { // second // level logger.logInfo(inner.getMessage()); throw (DITAOTException) inner; } if (currentFile.equals(inputFile)) { // stop the build if exception thrown when parsing input file. final MessageBean msgBean = MessageUtils.getMessage("DOTJ012F", params); msg = MessageUtils.getMessage("DOTJ012F", params).toString(); msg = new StringBuffer(msg).append(":").append(sax.getMessage()).toString(); throw new DITAOTException(msgBean, sax, msg); } final StringBuffer buff = new StringBuffer(); msg = MessageUtils.getMessage("DOTJ013E", params).toString(); buff.append(msg).append(LINE_SEPARATOR).append(sax.getMessage()); logger.logError(buff.toString()); } catch (final Exception e) { if (currentFile.equals(inputFile)) { // stop the build if exception thrown when parsing input file. final MessageBean msgBean = MessageUtils.getMessage("DOTJ012F", params); msg = MessageUtils.getMessage("DOTJ012F", params).toString(); msg = new StringBuffer(msg).append(":").append(e.getMessage()).toString(); throw new DITAOTException(msgBean, e, msg); } final StringBuffer buff = new StringBuffer(); msg = MessageUtils.getMessage("DOTJ013E", params).toString(); buff.append(msg).append(LINE_SEPARATOR).append(e.getMessage()); logger.logError(buff.toString()); } if (!reader.isValidInput() && currentFile.equals(inputFile)) { if (xmlValidate == true) { // stop the build if all content in the input file was filtered // out. msg = MessageUtils.getMessage("DOTJ022F", params).toString(); throw new DITAOTException(msg); } else { // stop the build if the content of the file is not valid. msg = MessageUtils.getMessage("DOTJ034F", params).toString(); throw new DITAOTException(msg); } } doneList.add(currentFile); reader.reset(); }
private void processChunk(final Element topicref, final File outputFile) { final String hrefValue = getValue(topicref, ATTRIBUTE_NAME_HREF); final Collection<String> chunkValue = split(getValue(topicref, ATTRIBUTE_NAME_CHUNK)); final String copytoValue = getValue(topicref, ATTRIBUTE_NAME_COPY_TO); final String scopeValue = getCascadeValue(topicref, ATTRIBUTE_NAME_SCOPE); final String classValue = getValue(topicref, ATTRIBUTE_NAME_CLASS); final String processRoleValue = getCascadeValue(topicref, ATTRIBUTE_NAME_PROCESSING_ROLE); File outputFileName = outputFile; Writer tempWriter = null; Set<String> tempTopicID = null; targetTopicId = null; selectMethod = CHUNK_SELECT_DOCUMENT; include = false; boolean needWriteDitaTag = true; try { String parseFilePath; if (copytoValue != null && !chunkValue.contains(CHUNK_TO_CONTENT)) { if (getFragment(hrefValue) != null) { parseFilePath = setFragment(copytoValue, getFragment(hrefValue)); } else { parseFilePath = copytoValue; } } else { parseFilePath = hrefValue; } // if @copy-to is processed in chunk module, the list file needs to // be updated. // Because @copy-to should be included in fulltopiclist, and the // source of coyy-to should be excluded in fulltopiclist. if (copytoValue != null && chunkValue.contains(CHUNK_TO_CONTENT) && hrefValue != null) { copyto.add(copytoValue); if (getFragment(hrefValue) != null) { copytoSource.add(stripFragment(hrefValue)); copytotarget2source.put(toURI(copytoValue), toURI(stripFragment(hrefValue))); } else { copytoSource.add(hrefValue); copytotarget2source.put(toURI(copytoValue), toURI(hrefValue)); } } if (parseFilePath != null && !ATTR_SCOPE_VALUE_EXTERNAL.equals(scopeValue)) { // now the path to target file make sense if (chunkValue.contains(CHUNK_TO_CONTENT)) { // if current element contains "to-content" in chunk // attribute // we need to create new buffer and flush the buffer to // file // after processing is finished tempWriter = output; tempTopicID = topicID; output = new StringWriter(); topicID = new HashSet<String>(); if (MAP_MAP.matches(classValue)) { // Very special case, we have a map element with // href value. // This is a map that needs to be chunked to // content. // No need to parse any file, just generate a stub // output. outputFileName = resolve(filePath, parseFilePath); needWriteDitaTag = false; } else if (copytoValue != null) { // use @copy-to value as the new file name outputFileName = resolve(filePath, copytoValue); } else if (hrefValue != null) { // try to use href value as the new file name if (chunkValue.contains(CHUNK_SELECT_TOPIC) || chunkValue.contains(CHUNK_SELECT_BRANCH)) { if (getFragment(hrefValue) != null) { // if we have an ID here, use it. outputFileName = resolve(filePath, getFragment(hrefValue) + FILE_EXTENSION_DITA); } else { // Find the first topic id in target file if // any. final String firstTopic = getFirstTopicId(resolve(filePath, hrefValue).getPath()); if (firstTopic != null) { outputFileName = resolve(filePath, firstTopic + FILE_EXTENSION_DITA); } else { outputFileName = resolve(filePath, hrefValue); } } } else { // otherwise, use the href value instead outputFileName = resolve(filePath, hrefValue); } } else { // use randomly generated file name outputFileName = resolve(filePath, generateFilename()); } // Check if there is any conflict if (outputFileName.exists() && !MAP_MAP.matches(classValue)) { final File t = outputFileName; outputFileName = resolve(filePath, generateFilename()); conflictTable.put(outputFileName.getPath(), t.getPath()); } // add newly generated file to changTable // the new entry in changeTable has same key and value // in order to indicate it is a newly generated file changeTable.put(outputFileName.getPath(), outputFileName.getPath()); } // "by-topic" couldn't reach here this.outputFile = outputFileName; final String path = resolveTopic(filePath, parseFilePath); // FIXME: Should be URI String newpath; if (getFragment(path) != null) { newpath = setFragment(outputFileName.getPath(), getFragment(path)); } else { final String firstTopicID = getFirstTopicId(path); if (firstTopicID != null) { newpath = setFragment(outputFileName.getPath(), firstTopicID); } else { newpath = outputFileName.getPath(); } } // add file name changes to changeTable, this will be // used in // TopicRefWriter's updateHref method, very important!!! changeTable.put(path, newpath); // update current element's @href value topicref.setAttribute( ATTRIBUTE_NAME_HREF, getRelativeUnixPath(filePath + UNIX_SEPARATOR + FILE_NAME_STUB_DITAMAP, newpath)); if (getFragment(parseFilePath) != null) { targetTopicId = getFragment(parseFilePath); } final String s = getChunkByToken(chunkValue, "select-", null); if (s != null) { selectMethod = s; // if the current topic href referred to a entire // topic file,it will be handled in "document" level. if (targetTopicId == null) { selectMethod = CHUNK_SELECT_DOCUMENT; } } final File tempPath = currentParsingFile; currentParsingFile = resolve(filePath, parseFilePath); if (!ATTR_PROCESSING_ROLE_VALUE_RESOURCE_ONLY.equals(processRoleValue)) { currentParsingFileTopicIDChangeTable = new HashMap<String, String>(); // TODO recursive point reader.parse(currentParsingFile.toURI().toString()); if (currentParsingFileTopicIDChangeTable.size() > 0) { final URI href = toURI(topicref.getAttribute(ATTRIBUTE_NAME_HREF)); final String pathtoElem = href.getFragment() != null ? href.getFragment() : ""; final String old_elementid = pathtoElem.contains(SLASH) ? pathtoElem.substring(0, pathtoElem.indexOf(SLASH)) : pathtoElem; if (!old_elementid.isEmpty()) { final String new_elementid = currentParsingFileTopicIDChangeTable.get(old_elementid); if (new_elementid != null && !new_elementid.isEmpty()) { topicref.setAttribute( ATTRIBUTE_NAME_HREF, setFragment(href, new_elementid).toString()); } } } currentParsingFileTopicIDChangeTable = null; } // restore the currentParsingFile currentParsingFile = tempPath; } if (topicref.hasChildNodes()) { // if current element has child nodes and chunk results for // this element has value // which means current element makes sense for chunk action. final StringWriter tempOutput = (StringWriter) output; output = new StringWriter(); final NodeList children = topicref.getChildNodes(); for (int i = 0; i < children.getLength(); i++) { final Node current = children.item(i); if (MAP_TOPICREF.matches(current)) { processChunk((Element) current, outputFileName); } } // merge results final StringBuffer parentResult = tempOutput.getBuffer(); final CharSequence tmpContent = ((StringWriter) output).getBuffer(); // Skip empty parents and @processing-role='resource-only' entries. // append into root topic if (parentResult.length() > 0 && parseFilePath != null && !ATTR_PROCESSING_ROLE_VALUE_RESOURCE_ONLY.equals(processRoleValue)) { insertAfter(hrefValue, parentResult, tmpContent); // replace contents } else { parentResult.append(tmpContent); } // restore back to parent's output this is a different temp output = tempOutput; } if (chunkValue.contains(CHUNK_TO_CONTENT)) { final String tmpContent = ((StringWriter) output).toString(); writeToContentChunk(tmpContent, outputFileName, needWriteDitaTag); // restore back original output output = tempWriter; topicID = tempTopicID; } } catch (final RuntimeException e) { throw e; } catch (final Exception e) { logger.error(e.getMessage(), e); } }
/** * Write result files. * * @throws DITAOTException if writing result files failed */ private void outputResult() throws DITAOTException { final File dir = new File(tempDir); if (!dir.exists()) { dir.mkdirs(); } Job prop = null; try { prop = new Job(dir); } catch (final IOException e) { throw new DITAOTException("Failed to create empty job: " + e.getMessage(), e); } prop.setProperty(INPUT_DIR, baseInputDir); prop.setProperty(INPUT_DITAMAP, prefix + inputFile); prop.setProperty(INPUT_DITAMAP_LIST_FILE_LIST, USER_INPUT_FILE_LIST_FILE); final File inputfile = new File(tempDir, USER_INPUT_FILE_LIST_FILE); Writer bufferedWriter = null; try { bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(inputfile))); bufferedWriter.write(prefix + inputFile); bufferedWriter.flush(); } catch (final FileNotFoundException e) { logger.logException(e); } catch (final IOException e) { logger.logException(e); } finally { if (bufferedWriter != null) { try { bufferedWriter.close(); } catch (final IOException e) { logger.logException(e); } } } // add out.dita.files,tempdirToinputmapdir.relative.value to solve the // output problem relativeValue = prefix; formatRelativeValue = formatRelativeValue(relativeValue); prop.setProperty("tempdirToinputmapdir.relative.value", formatRelativeValue); prop.setProperty("uplevels", getUpdateLevels()); addSetToProperties(prop, OUT_DITA_FILES_LIST, outDitaFilesSet); addSetToProperties(prop, FULL_DITAMAP_TOPIC_LIST, ditaSet); addSetToProperties(prop, FULL_DITA_TOPIC_LIST, fullTopicSet); addSetToProperties(prop, FULL_DITAMAP_LIST, fullMapSet); addSetToProperties(prop, HREF_DITA_TOPIC_LIST, hrefTopicSet); addSetToProperties(prop, CONREF_LIST, conrefSet); addSetToProperties(prop, IMAGE_LIST, imageSet); addSetToProperties(prop, FLAG_IMAGE_LIST, flagImageSet); addSetToProperties(prop, HTML_LIST, htmlSet); addSetToProperties(prop, HREF_TARGET_LIST, hrefTargetSet); addSetToProperties(prop, HREF_TOPIC_LIST, hrefWithIDSet); addSetToProperties(prop, CHUNK_TOPIC_LIST, chunkTopicSet); addSetToProperties(prop, SUBJEC_SCHEME_LIST, schemeSet); addSetToProperties(prop, CONREF_TARGET_LIST, conrefTargetSet); addSetToProperties(prop, COPYTO_SOURCE_LIST, copytoSourceSet); addSetToProperties(prop, SUBSIDIARY_TARGET_LIST, subsidiarySet); addSetToProperties(prop, CONREF_PUSH_LIST, conrefpushSet); addSetToProperties(prop, KEYREF_LIST, keyrefSet); addSetToProperties(prop, CODEREF_LIST, coderefSet); // @processing-role addSetToProperties(prop, RESOURCE_ONLY_LIST, resourceOnlySet); addFlagImagesSetToProperties(prop, REL_FLAGIMAGE_LIST, relFlagImagesSet); // Convert copyto map into set and output final Set<String> copytoSet = new HashSet<String>(INT_128); for (final Map.Entry<String, String> entry : copytoMap.entrySet()) { copytoSet.add(entry.toString()); } addSetToProperties(prop, COPYTO_TARGET_TO_SOURCE_MAP_LIST, copytoSet); addKeyDefSetToProperties(prop, KEY_LIST, keysDefMap.values()); try { logger.logInfo("Serializing job specification"); prop.write(); } catch (final IOException e) { throw new DITAOTException( "Failed to serialize job configuration files: " + e.getMessage(), e); } // Output relation-graph writeMapToXML(reader.getRelationshipGrap(), FILE_NAME_SUBJECT_RELATION); // Output topic-scheme dictionary writeMapToXML(this.schemeDictionary, FILE_NAME_SUBJECT_DICTIONARY); // added by Willam on 2009-07-17 for req #12014 start if (INDEX_TYPE_ECLIPSEHELP.equals(transtype)) { // Output plugin id final File pluginIdFile = new File(tempDir, FILE_NAME_PLUGIN_XML); final DelayConrefUtils delayConrefUtils = new DelayConrefUtils(); delayConrefUtils.writeMapToXML(reader.getPluginMap(), pluginIdFile); // write the result into the file final StringBuffer result = reader.getResult(); try { export.write(result.toString()); } catch (final IOException e) { logger.logException(e); } } // added by Willam on 2009-07-17 for req #12014 end }
/** * Escape regular expression special characters. * * @param value input * @return input with regular expression special characters escaped */ private String formatRelativeValue(final String value) { final StringBuffer buff = new StringBuffer(); if (value == null || value.length() == 0) { return ""; } int index = 0; // $( )+.[^{\ while (index < value.length()) { final char current = value.charAt(index); switch (current) { case '.': buff.append("\\."); break; // case '/': // case '|': case '\\': buff.append("[\\\\|/]"); break; case '(': buff.append("\\("); break; case ')': buff.append("\\)"); break; case '[': buff.append("\\["); break; case ']': buff.append("\\]"); break; case '{': buff.append("\\{"); break; case '}': buff.append("\\}"); break; case '^': buff.append("\\^"); break; case '+': buff.append("\\+"); break; case '$': buff.append("\\$"); break; default: buff.append(current); } index++; } return buff.toString(); }