@Override
  public void write(final File filename) throws DITAOTException {
    // pass map's directory path
    filePath = filename;
    final String hrefValue = getValue(rootTopicref, ATTRIBUTE_NAME_HREF);
    final String copytoValue = getValue(rootTopicref, ATTRIBUTE_NAME_COPY_TO);
    final String scopeValue = getCascadeValue(rootTopicref, ATTRIBUTE_NAME_SCOPE);
    // Chimera path, has fragment
    String parseFilePath;
    final Collection<String> chunkValue = split(getValue(rootTopicref, ATTRIBUTE_NAME_CHUNK));
    final String processRoleValue = getCascadeValue(rootTopicref, ATTRIBUTE_NAME_PROCESSING_ROLE);
    boolean dotchunk = false;

    if (copytoValue != null && !chunkValue.contains(CHUNK_TO_CONTENT)) {
      if (hrefValue != null && 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)) {
      copyto.add(copytoValue);
      if (hrefValue != null && getFragment(hrefValue) != null) {
        copytoSource.add(stripFragment(hrefValue));
        copytotarget2source.put(toURI(copytoValue), toURI(stripFragment(hrefValue)));
      } else {
        copytoSource.add(hrefValue);
        copytotarget2source.put(toURI(copytoValue), toURI(hrefValue));
      }
    }
    try {
      if (parseFilePath != null
          && !ATTR_SCOPE_VALUE_EXTERNAL.equals(scopeValue)
          && !ATTR_PROCESSING_ROLE_VALUE_RESOURCE_ONLY.equals(processRoleValue)) {
        // if the path to target file make sense
        currentParsingFile = resolve(filePath, parseFilePath);
        File outputFileName;
        /*
         * FIXME: we have code flaws here, references in ditamap need to
         * be updated to new created file.
         */
        String id = null;
        String firstTopicID = null;
        if (getFragment(parseFilePath) != null) {
          id = getFragment(parseFilePath);
          if (chunkValue.contains(CHUNK_SELECT_BRANCH)) {
            outputFileName = resolve(filePath, id + FILE_EXTENSION_DITA);
            targetTopicId = id;
            startFromFirstTopic = false;
            selectMethod = CHUNK_SELECT_BRANCH;
          } else if (chunkValue.contains(CHUNK_SELECT_DOCUMENT)) {
            firstTopicID = getFirstTopicId(resolve(filePath, parseFilePath).getPath());

            topicDoc = getTopicDoc(resolve(filePath, parseFilePath).getPath());

            if (firstTopicID != null) {
              outputFileName = resolve(filePath, firstTopicID + FILE_EXTENSION_DITA);
              targetTopicId = firstTopicID;
            } else {
              outputFileName = new File(currentParsingFile.getPath() + FILE_EXTENSION_CHUNK);
              dotchunk = true;
              targetTopicId = null;
            }
            selectMethod = CHUNK_SELECT_DOCUMENT;
          } else {
            outputFileName = resolve(filePath, id + FILE_EXTENSION_DITA);
            targetTopicId = id;
            startFromFirstTopic = false;
            selectMethod = CHUNK_SELECT_TOPIC;
          }
        } else {
          firstTopicID = getFirstTopicId(resolve(filePath, parseFilePath).getPath());

          topicDoc = getTopicDoc(resolve(filePath, parseFilePath).getPath());

          if (firstTopicID != null) {
            outputFileName = resolve(filePath, firstTopicID + FILE_EXTENSION_DITA);
            targetTopicId = firstTopicID;
          } else {
            outputFileName = new File(currentParsingFile.getPath() + FILE_EXTENSION_CHUNK);
            dotchunk = true;
            targetTopicId = null;
          }
          selectMethod = CHUNK_SELECT_DOCUMENT;
        }
        if (copytoValue != null) {
          // use @copy-to value as the new file name
          outputFileName = resolve(filePath, copytoValue);
        }

        if (outputFileName.exists()) {
          final File t = outputFileName;
          outputFileName = resolve(filePath, generateFilename());
          conflictTable.put(outputFileName.getPath(), t.getPath());
          dotchunk = false;
        }
        output = new OutputStreamWriter(new FileOutputStream(outputFileName), UTF8);
        outputFile = outputFileName;
        if (!dotchunk) {
          changeTable.put(
              resolveTopic(filePath, parseFilePath), setFragment(outputFileName.getPath(), id));
          // new generated file
          changeTable.put(outputFileName.getPath(), outputFileName.getPath());
        }
        // change the href value
        if (firstTopicID == null) {
          rootTopicref.setAttribute(
              ATTRIBUTE_NAME_HREF,
              setFragment(
                      toURI(
                          getRelativePath(
                              new File(filePath, FILE_NAME_STUB_DITAMAP), outputFileName)),
                      id)
                  .toString());
        } else {
          rootTopicref.setAttribute(
              ATTRIBUTE_NAME_HREF,
              setFragment(
                      toURI(
                          getRelativePath(
                              new File(filePath, FILE_NAME_STUB_DITAMAP), outputFileName)),
                      firstTopicID)
                  .toString());
        }
        include = false;
        // just a mark?
        stub = rootTopicref.getOwnerDocument().createElement(ELEMENT_STUB);
        siblingStub = rootTopicref.getOwnerDocument().createElement(ELEMENT_STUB);
        // <element>
        // <stub/>
        // ...
        // </element>
        // <siblingstub/>
        // ...
        // Place stub
        if (rootTopicref.hasChildNodes()) {
          final NodeList list = rootTopicref.getElementsByTagName(MAP_TOPICMETA.localName);
          if (list.getLength() > 0) {
            final Node node = list.item(0);
            final Node nextSibling = node.getNextSibling();
            // no sibling so node is the last child
            if (nextSibling == null) {
              node.getParentNode().appendChild(stub);
            } else {
              // has sibling node
              node.getParentNode().insertBefore(stub, nextSibling);
            }
          } else {
            // no topicmeta tag.
            rootTopicref.insertBefore(stub, rootTopicref.getFirstChild());
          }

          // element.insertBefore(stub,element.getFirstChild());
        } else {
          rootTopicref.appendChild(stub);
        }

        // Place siblingStub
        if (rootTopicref.getNextSibling() != null) {
          rootTopicref.getParentNode().insertBefore(siblingStub, rootTopicref.getNextSibling());
        } else {
          rootTopicref.getParentNode().appendChild(siblingStub);
        }

        reader.setErrorHandler(new DITAOTXMLErrorHandler(currentParsingFile.getPath(), logger));
        reader.parse(currentParsingFile.toURI().toString());
        output.flush();

        // remove stub and siblingStub
        stub.getParentNode().removeChild(stub);
        siblingStub.getParentNode().removeChild(siblingStub);
      }
    } catch (final RuntimeException e) {
      throw e;
    } catch (final Exception e) {
      logger.error(e.getMessage(), e);
    } finally {
      try {
        if (output != null) {
          output.close();
          output = null;
          if (dotchunk && !currentParsingFile.delete()) {
            logger.error(
                MessageUtils.getInstance()
                    .getMessage("DOTJ009E", currentParsingFile.getPath(), outputFile.getPath())
                    .toString());
          }
          if (dotchunk && !outputFile.renameTo(currentParsingFile)) {
            logger.error(
                MessageUtils.getInstance()
                    .getMessage("DOTJ009E", currentParsingFile.getPath(), outputFile.getPath())
                    .toString());
          }
        }
      } catch (final Exception ex) {
        logger.error(ex.getMessage(), ex);
      }
    }
    if (!copyto.isEmpty()) {
      updateList();
    }
  }
Esempio n. 2
0
  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);
    }
  }