Package com.puppetlabs.xtext.serializer

Source Code of com.puppetlabs.xtext.serializer.DomBasedSerializer$StringBuilderWriter

/**
* Copyright (c) 2013 Puppet Labs, Inc. and other contributors, as listed below.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*   Puppet Labs
*/
package com.puppetlabs.xtext.serializer;

import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import com.puppetlabs.xtext.dommodel.DomModelUtils;
import com.puppetlabs.xtext.dommodel.IDomNode;
import com.puppetlabs.xtext.dommodel.formatter.IDomModelFormatter;
import com.puppetlabs.xtext.dommodel.formatter.comments.ICommentConfiguration;
import com.puppetlabs.xtext.dommodel.formatter.context.IFormattingContextFactory;
import com.puppetlabs.xtext.dommodel.formatter.context.IFormattingContextFactory.FormattingOption;
import com.puppetlabs.xtext.resource.ResourceAccessScope;
import com.puppetlabs.xtext.serializer.acceptor.DomModelSequenceAdapter;
import com.puppetlabs.xtext.serializer.acceptor.IHiddenTokenSequencer2;
import org.eclipse.emf.common.util.Diagnostic;
import org.eclipse.emf.ecore.EObject;
import org.eclipse.xtext.formatting.ILineSeparatorInformation;
import org.eclipse.xtext.nodemodel.ICompositeNode;
import org.eclipse.xtext.nodemodel.util.NodeModelUtils;
import org.eclipse.xtext.parsetree.reconstr.ICommentAssociater;
import org.eclipse.xtext.parsetree.reconstr.IHiddenTokenHelper;
import org.eclipse.xtext.parsetree.reconstr.ITokenStream;
import org.eclipse.xtext.resource.SaveOptions;
import org.eclipse.xtext.serializer.acceptor.ISemanticSequenceAcceptor;
import org.eclipse.xtext.serializer.acceptor.ISequenceAcceptor;
import org.eclipse.xtext.serializer.acceptor.ISyntacticSequenceAcceptor;
import org.eclipse.xtext.serializer.acceptor.TokenStreamSequenceAdapter;
import org.eclipse.xtext.serializer.diagnostic.ISerializationDiagnostic;
import org.eclipse.xtext.serializer.impl.Serializer;
import org.eclipse.xtext.serializer.sequencer.IHiddenTokenSequencer;
import org.eclipse.xtext.serializer.sequencer.ISemanticSequencer;
import org.eclipse.xtext.serializer.sequencer.ISyntacticSequencer;
import org.eclipse.xtext.util.ITextRegion;
import org.eclipse.xtext.util.ReplaceRegion;
import org.eclipse.xtext.util.TextRegion;
import org.eclipse.xtext.validation.IConcreteSyntaxValidator;

import com.google.inject.Inject;

/**
* Extends Serializer and modifies the API (ITokenStream based formatting/output not supported).
* Use Serializer methods that does not take ITokenStream as an argument.
* TODO: This is a temporary solution.
*
*/
public class DomBasedSerializer extends Serializer {

  protected static class StringBuilderWriter extends Writer {
    private final StringBuilder builder;

    public StringBuilderWriter() {
      builder = new StringBuilder();
    }

    public StringBuilderWriter(int initialCapacity) {
      builder = new StringBuilder(initialCapacity);
    }

    public StringBuilderWriter(StringBuilder appendToBuilder) {
      builder = appendToBuilder;
    }

    @Override
    public Writer append(char value) {
      builder.append(value);
      return this;
    }

    @Override
    public Writer append(CharSequence value) {
      builder.append(value);
      return this;
    }

    @Override
    public Writer append(CharSequence value, int start, int end) {
      builder.append(value, start, end);
      return this;
    }

    @Override
    public void close() throws IOException {
      // does nothing
    }

    @Override
    public void flush() throws IOException {
      // does nothing
    }

    StringBuilder getBuilder() {
      return builder;
    }

    @Override
    public String toString() {
      return builder.toString();
    }

    @Override
    public void write(char[] cbuf, int off, int len) throws IOException {
      builder.append(cbuf, off, len);
    }

    @Override
    public void write(String value) {
      builder.append(value);
    }
  }

  @Inject
  IDomModelFormatter domFormatter;

  @Inject
  IFormattingContextFactory formattingContextFactory;

  @Inject
  IHiddenTokenHelper hiddenTokenHelper;

  @Inject
  ILineSeparatorInformation lineSeparatorInformation;

  @Inject
  ICommentConfiguration<?> commentConfiguration;

  @Inject
  private ResourceAccessScope resourceScope;

  @Inject
  ICommentAssociater commentAssociater;

  @Inject
  CommentAssociator ppCommentAssociator;

  private FormattingOption formatting(SaveOptions options) {
    return options.isFormatting()
        ? FormattingOption.Format
        : FormattingOption.PreserveWhitespace;
  }

  /**
   * NOTE: This overridden method is required to initialize the DomModelSequences.
   * The base implementation checks if the tokens parameter is a specific adapter, and
   * then initializes it. This method does the same but for DomModelSequenceAdapter.
   *
   */
  @Override
  protected void serialize(EObject semanticObject, EObject context, ISequenceAcceptor tokens,
      ISerializationDiagnostic.Acceptor errors) {
    serialize(semanticObject, context, tokens, errors, null);
  }

  protected void serialize(EObject semanticObject, EObject context, ISequenceAcceptor tokens,
      ISerializationDiagnostic.Acceptor errors, ICommentReconcilement commentReconciliator) {
    ISemanticSequencer semantic = semanticSequencerProvider.get();
    ISyntacticSequencer syntactic = syntacticSequencerProvider.get();
    IHiddenTokenSequencer hidden = hiddenTokenSequencerProvider.get();
    semantic.init((ISemanticSequenceAcceptor) syntactic, errors);
    syntactic.init(context, semanticObject, (ISyntacticSequenceAcceptor) hidden, errors);
    if(hidden instanceof IHiddenTokenSequencer2)
      ((IHiddenTokenSequencer2) hidden).init(context, semanticObject, tokens, errors, commentReconciliator);
    else
      hidden.init(context, semanticObject, tokens, errors);

    // NOTE: This is not so nice
    if(tokens instanceof TokenStreamSequenceAdapter)
      ((TokenStreamSequenceAdapter) tokens).init(context);
    else if(tokens instanceof DomModelSequenceAdapter)
      ((DomModelSequenceAdapter) tokens).init(context, semanticObject);

    semantic.createSequence(context, semanticObject);
  }

  /**
   * @throws UnsupportedOperationException
   */
  @Override
  protected void serialize(EObject obj, ITokenStream tokenStream, SaveOptions options) throws IOException {
    throw new UnsupportedOperationException("Use new API");
  }

  @Override
  public String serialize(EObject obj, SaveOptions options) {
    return serialize(obj, options, null);
  }

  public String serialize(EObject obj, SaveOptions options, ITextRegion regionToFormat) {
    // TODO: Faster to use a non synchronizing implementation such as StringBuilderWriter from apache commons io
    Writer writer = new StringBuilderWriter();
    try {
      serialize(obj, writer, options, regionToFormat);
    }
    catch(IOException e) {
      throw new RuntimeException(e);
    }
    return writer.toString();
  }

  @Override
  public void serialize(EObject obj, Writer writer, SaveOptions options) throws IOException {
    serialize(obj, writer, options, null /* all text */);
  }

  public void serialize(EObject obj, Writer writer, SaveOptions options, ITextRegion regionToFormat)
      throws IOException {

    // FROM SUPER VERSION (without the ITextRegion)
    // use the CSV as long as there are cases where is provides better messages than the serializer itself.
    if(options.isValidating()) {
      List<Diagnostic> diagnostics = new ArrayList<Diagnostic>();
      validator.validateRecursive(
        obj, new IConcreteSyntaxValidator.DiagnosticListAcceptor(diagnostics), new HashMap<Object, Object>());
      if(!diagnostics.isEmpty())
        throw new IConcreteSyntaxValidator.InvalidConcreteSyntaxException(
          "These errors need to be fixed before the model can be serialized.", diagnostics);
    }
    // END FROM SUPER VERSION

    // Uses DomModelSequencer and new formatter interface
    ISerializationDiagnostic.Acceptor errors = ISerializationDiagnostic.EXCEPTION_THROWING_ACCEPTOR;
    DomModelSequenceAdapter acceptor = new DomModelSequenceAdapter(
      hiddenTokenHelper, commentConfiguration, lineSeparatorInformation, errors);
    EObject context = getContext(obj);
    serialize(obj, context, acceptor, errors);
    ReplaceRegion r = domFormatter.format(
      acceptor.getDomModel(), regionToFormat, formattingContextFactory.create(obj, formatting(options)), errors);
    writer.append(r.getText());
  }

  @Override
  public ReplaceRegion serializeReplacement(EObject obj, SaveOptions options) {
    ICompositeNode node = NodeModelUtils.findActualNodeFor(obj);

    if(node == null) {
      throw new IllegalStateException("Cannot replace an obj that has no associated node");
    }

    ICommentReconcilement commentReconciliator = ppCommentAssociator.associateComments(node);

    boolean alreadyEnteredResourceScope = false;
    try {
      if(resourceScope.get().getResourceURI() == null) {
        alreadyEnteredResourceScope = true;
        resourceScope.enter(obj.eResource());
      }
      // Serialize everything to DOM
      IDomNode root = serializeToDom(obj.eResource().getContents().get(0), true, commentReconciliator);

      // Find the node for the modified object, we need to format the region it occupies.
      IDomNode replacementNode = DomModelUtils.findNodeForSemanticObject(root, obj);
      TextRegion regionToFormat = new TextRegion(replacementNode.getOffset(), replacementNode.getLength());

      // Override temporarily to have formatting turned on
      // GAH - this is just ridiculous internal DSL junk to set a single boolean
      options = SaveOptions.newBuilder().format().getOptions();
      ReplaceRegion r = domFormatter.format(
        root, regionToFormat,
        formattingContextFactory.create(obj.eResource().getContents().get(0), formatting(options)));
      // String text = serialize(obj.eContainer(), options, new TextRegion(node.getOffset(), node.getLength()));
      return new ReplaceRegion(node.getTotalOffset(), node.getTotalLength(), r.getText());
    }
    finally {
      if(alreadyEnteredResourceScope)
        resourceScope.exit();
    }
  }

  /**
   * Serialize and return the resulting DOM. This is the same as calling {@link #serializeToDom(EObject, boolean, ICommentReconcilement)} with a
   * null ICommentReconciliator.
   *
   * @param obj
   * @param preserveWhitespace
   * @return
   */
  public IDomNode serializeToDom(EObject obj, boolean preserveWhitespace) {
    return serializeToDom(obj, preserveWhitespace, null);
  }

  /**
   * Serialize and return the resulting DOM.
   *
   * @param obj
   * @param preserveWhitespace
   * @return
   */
  public IDomNode serializeToDom(EObject obj, boolean preserveWhitespace, ICommentReconcilement commentReconciliator) {
    // Uses DomModelSequencer and new formatter interface
    ISerializationDiagnostic.Acceptor errors = ISerializationDiagnostic.EXCEPTION_THROWING_ACCEPTOR;
    DomModelSequenceAdapter acceptor = new DomModelSequenceAdapter(
      hiddenTokenHelper, commentConfiguration, lineSeparatorInformation, errors);
    EObject context = getContext(obj);
    serialize(obj, context, acceptor, errors, commentReconciliator);
    return acceptor.getDomModel();
  }
}
TOP

Related Classes of com.puppetlabs.xtext.serializer.DomBasedSerializer$StringBuilderWriter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.