Package qwickie.builder

Source Code of qwickie.builder.QWickieBuilder$QWickieDeltaVisitor

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License.  You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package qwickie.builder;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IMarker;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.resources.IResourceDelta;
import org.eclipse.core.resources.IResourceDeltaVisitor;
import org.eclipse.core.resources.IResourceVisitor;
import org.eclipse.core.resources.IncrementalProjectBuilder;
import org.eclipse.core.runtime.Assert;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Status;
import org.eclipse.jdt.core.IClassFile;
import org.eclipse.jdt.core.JavaModelException;
import org.eclipse.jdt.core.dom.IVariableBinding;
import org.eclipse.jdt.internal.core.JavaElement;
import org.eclipse.jdt.internal.core.ResolvedBinaryType;
import org.eclipse.jdt.internal.core.ResolvedSourceType;
import org.eclipse.jface.preference.IPreferenceStore;
import org.eclipse.jface.text.FindReplaceDocumentAdapter;
import org.eclipse.jface.text.IDocument;
import org.eclipse.jface.text.IRegion;
import org.eclipse.ui.editors.text.TextFileDocumentProvider;
import org.eclipse.ui.texteditor.IDocumentProvider;

import qwickie.QWickieActivator;
import qwickie.hyperlink.WicketHyperlink;
import qwickie.preferences.QWickiePreferencePage;
import qwickie.util.DocumentHelper;
import qwickie.util.FileSearcher;
import qwickie.util.TypeHelper;

@SuppressWarnings("restriction")
public class QWickieBuilder extends IncrementalProjectBuilder {

  private final IPreferenceStore store = QWickieActivator.getDefault().getPreferenceStore();
  private String[] excludes = new String[] {};

  private static int LDL = System.getProperty("line.separator").length();
  public static final String BUILDER_ID = "qwickie.qwickieBuilder";
  public static final String MARKER_TYPE = "qwickie.qwickieProblem";
  public static final String MARKER_ATTRIB_WICKET_ID = "wicketId";
  public static final String MARKER_ATTRIB_HTML_SNIPPET = "htmlSnippet";
  private static final String JAVA_EXT = "java";
  private static final String HTML_EXT = "html";
  private List<IPath> srcFolders = new ArrayList<IPath>();
  private int severity = 2;

  class QWickieDeltaVisitor implements IResourceDeltaVisitor {
    /*
     * (non-Javadoc)
     *
     * @see org.eclipse.core.resources.IResourceDeltaVisitor#visit(org.eclipse.core.resources.IResourceDelta)
     */
    public boolean visit(final IResourceDelta delta) throws CoreException {
      final IResource resource = delta.getResource();
      if (resource == null) {
        return true;
      }

      switch (delta.getKind()) {
      case IResourceDelta.ADDED:
        // handle added resource
        checkWicketIds(resource);
        break;
      case IResourceDelta.REMOVED:
        // handle removed resource
        break;
      case IResourceDelta.CHANGED:
        // handle changed resource
        checkWicketIds(resource);
        break;
      }
      // return true to continue visiting children.
      return true;
    }
  }

  class QWickieResourceVisitor implements IResourceVisitor {
    public boolean visit(final IResource resource) {
      checkWicketIds(resource);
      // return true to continue visiting children.
      return true;
    }
  }

  private void addMarker(final IFile file, final String message, final String wid, final String htmlSnippet, int lineNumber, final int startChar,
      final int length) {
    try {
      final IMarker marker = file.createMarker(MARKER_TYPE);
      marker.setAttribute(MARKER_ATTRIB_WICKET_ID, wid);
      marker.setAttribute(MARKER_ATTRIB_HTML_SNIPPET, htmlSnippet);
      marker.setAttribute(IMarker.MESSAGE, message);
      marker.setAttribute(IMarker.PRIORITY, IMarker.PRIORITY_NORMAL);
      marker.setAttribute(IMarker.SEVERITY, severity);
      if (lineNumber == -1) {
        lineNumber = 1;
      }
      marker.setAttribute(IMarker.LINE_NUMBER, lineNumber);
      marker.setAttribute(IMarker.PROBLEM, true);
      marker.setAttribute(IMarker.CHAR_START, startChar);
      marker.setAttribute(IMarker.CHAR_END, startChar + length);
    } catch (final CoreException e) {
    }
  }

  /*
   * (non-Javadoc)
   *
   * @see org.eclipse.core.internal.events.InternalBuilder#build(int, java.util.Map, org.eclipse.core.runtime.IProgressMonitor)
   */
  @Override
  protected IProject[] build(final int kind, final Map<String, String> args, final IProgressMonitor monitor) throws CoreException {
    srcFolders = FileSearcher.getSourceFolders(getProject());
    excludes = store.getString("excludes").split(",");
    if (kind == FULL_BUILD) {
      fullBuild(monitor);
    } else {
      final IResourceDelta delta = getDelta(getProject());
      if (delta == null) {
        fullBuild(monitor);
      } else {
        incrementalBuild(delta, monitor);
      }
    }
    return null;
  }

  void checkWicketIds(final IResource resource) {
    if (resource == null || !(resource instanceof IFile) || isExcluded((IFile) resource)) {
      return;
    }
    if (srcFolders.isEmpty()) {
      srcFolders = FileSearcher.getSourceFolders(getProject());
    }
    if (excludes.length == 0) {
      excludes = store.getString("excludes").split(",");
    }

    final String fileExtension = resource.getFileExtension();
    // check html files, that are in the source folders
    if (HTML_EXT.equals(fileExtension)) {
      final IFile htmlFile = (IFile) resource;
      final IFile javaFile = WicketHyperlink.getJavaFile(resource);
      deleteMarkers(htmlFile);
      deleteMarkers(javaFile);
      if (isExcluded(javaFile)) {
        return;
      }

      try {
        final IDocumentProvider provider = new TextFileDocumentProvider();
        provider.connect(htmlFile);
        final IDocument document = provider.getDocument(htmlFile);
        LDL = document.getLineDelimiter(0).length();
        int sc = 0;
        boolean commented = false;
        String wid_const = DocumentHelper.WICKET;
        for (int i = 0; i < document.getNumberOfLines(); i++) {
          final IRegion li = document.getLineInformation(i);
          final String line = document.get(li.getOffset(), li.getLength());

          if (line.contains("<!--")) {
            commented = true;
            continue;
          }
          if (line.contains("-->")) {
            commented = false;
            continue;
          }

          if (line.contains(QWickieActivator.WICKET_DTD)) {
            wid_const = DocumentHelper.getWicketNamespace(line);
          }

          final String wid_const_id = wid_const + ":id=\"";
          if (line.contains(wid_const_id) && !commented) {
            final String wid = line.split(wid_const_id)[1].split("\"")[0];
            int jlc = getJavaLine(javaFile, wid);
            if (jlc == -1) { // wicket id was not found in this java file
              // get the supertypes for the WebPage (maybe it's added in a BasePage?)
              final List<Object> superTypes = TypeHelper.getSupertypes(javaFile);
              for (final Object superType : superTypes) {
                if (superType instanceof IFile) {
                  jlc = getJavaLine((IFile) superType, wid);
                } else if (superType instanceof IClassFile) {
                  jlc = getJavaLine((IClassFile) superType, wid);
                }
                if (jlc == -1) {
                  // not found, then search in the used types
                  final List<JavaElement> wcts = TypeHelper.getWicketComponentTypes(javaFile);
                  for (final JavaElement wct : wcts) {
                    jlc = getJavaLine(wct, wid);
                    if (jlc > -1) {
                      break;
                    }
                  }
                  if (jlc == -1) {
                    // not found, then search in the used models
                    final List<IVariableBinding> wmts = TypeHelper.getWicketModelTypes(javaFile);
                    for (final IVariableBinding wmt : wmts) {
                      if (wid.equals(wmt.getName())) {
                        jlc = 0;
                        break;
                      }
                    }
                  }
                }
                if (jlc > -1) { // found, so don't go further
                  break;
                }
              }
              if (jlc == -1) {
                final int widPos = sc + line.indexOf("\"" + wid + "\"") + 1;
                FindReplaceDocumentAdapter frda = new FindReplaceDocumentAdapter(document);
                IRegion tagBegin = frda.find(widPos, "<", false, true, false, false);
                IRegion tagEnd = frda.find(tagBegin.getOffset(), " ", true, true, false, false);
                String htmlTag = document.get(tagBegin.getOffset() + 1, tagEnd.getOffset() - tagBegin.getOffset() - 1);
                String htmlSnippet = htmlTag.toLowerCase();
                if (htmlFile != null && "input".equals(htmlSnippet)) {
                  tagEnd = frda.find(tagBegin.getOffset(), ">", true, true, false, false);
                  htmlSnippet = document.get(tagBegin.getOffset() + 1, tagEnd.getOffset() - tagBegin.getOffset() - 1).toLowerCase().trim();
                  if (htmlSnippet.contains("type")) {
                    final String[] hss = htmlSnippet.split(" ");
                    if (hss != null) {
                      for (int j = 0; j < hss.length; j++) {
                        String hs = hss[j];
                        if (hs.startsWith("type")) {
                          htmlSnippet = htmlTag + " " + hs.replace("type=", "").split("\"")[1];
                        }
                      }
                    }
                  } else {
                    htmlSnippet = htmlTag.toLowerCase();
                  }
                }
                addMarker(htmlFile, getErrorText(wid), wid, htmlSnippet, i, widPos, wid.length());
                markJava(javaFile, wid, htmlSnippet);
              }
            }
          }
          sc += li.getLength() + LDL;
        }
        provider.disconnect(htmlFile);
      } catch (final Exception e) {
        QWickieActivator.getDefault().getLog().log(new Status(Status.ERROR, QWickieActivator.PLUGIN_ID, "Error in builder", e));
      }
    }

    // check java files
    if (JAVA_EXT.equals(fileExtension)) {
      final List<String> htmlFilenames = WicketHyperlink.getHtmlFiles(resource);
      for (String htmlFilename : htmlFilenames) {
        final IFile htmlFile = WicketHyperlink.getFile(htmlFilename);
        checkWicketIds(htmlFile);
      }
    }
  }

  /**
   * Is this file excluded from beeing checked
   */
  private boolean isExcluded(final IFile file) {
    for (String exclude : excludes) {
      if (exclude.length() > 0 && file != null && file.getProjectRelativePath().toString().startsWith(exclude)) {
        return true;
      }
    }
    return !isSource(file);
  }

  /**
   * mark an error in a java file
   */
  private void markJava(final IFile javaFile, final String wid, final String htmlSnippet) {
    final IDocumentProvider provider = new TextFileDocumentProvider();
    try {
      provider.connect(javaFile);
      final IDocument document = provider.getDocument(javaFile);
      final String className = javaFile.getName().replaceAll(".java", "");
      final FindReplaceDocumentAdapter frda = new FindReplaceDocumentAdapter(document);
      final IRegion region = frda.find(0, "class " + className, true, true, true, false);
      if (region != null) {
        addMarker(javaFile, getErrorText(wid), wid, htmlSnippet, document.getLineOfOffset(region.getOffset()), region.getOffset() + 6,
            className.length());
      }
      provider.disconnect(javaFile);
    } catch (final Exception e) {
    }
  }

  /** get the error text that is displayed */
  private String getErrorText(final String wid) {
    return QWickieActivator.WICKET_ID + " \"" + wid + "\" not found in java file(s)";
  }

  /** search for the line, containing the wicket:id in a java file */
  private int getJavaLine(final IFile javaFile, final String wid) {
    try {
      final InputStream contents = javaFile.getContents(true);
      final BufferedReader br = new BufferedReader(new InputStreamReader(contents));
      final char[] c = new char[contents.available()];
      br.read(c);
      br.close();
      contents.close();
      return getJavaLine(new String(c), wid);
    } catch (final Exception e) {
    }
    return -1;
  }

  private int getJavaLine(final JavaElement je, final String wid) {
    Assert.isNotNull(je);
    try {
      if (je instanceof ResolvedBinaryType) {
        ResolvedBinaryType rbt = (ResolvedBinaryType) je;
        String source = rbt.getSource(); // try to get the source
        // shorten search for know wicket:ids
        if ((je.getElementName().equals("FilterToolbar") && ("focus-tracker".equals(wid) || "focus-restore".equals(wid)))
            || ("cols".equals(wid) && je.getElementName().equals("GridView"))) {
          return 1;
        }
        return getJavaLine(source, wid);
      }
      if (je instanceof ResolvedSourceType) {
        return getJavaLine(((ResolvedSourceType) je).getSource(), wid);
      }
      return getJavaLine(je.getClassFile().getSource(), wid);
    } catch (final JavaModelException e) {
    }
    return -1;
  }

  /** search for the line, containing the wicket:id in a java file */
  private int getJavaLine(final IClassFile classFile, final String wid) {
    Assert.isNotNull(classFile);
    try {
      return getJavaLine(classFile.getSource(), wid);
    } catch (final JavaModelException e) {
    }
    return -1;
  }

  private boolean lineContains(final String line, final String wid) {
    return line.contains("\"" + wid + "\"");
  }

  private int getJavaLine(final String source, final String wid) {
    int lc = -1;
    if (source == null) {
      return -1;
    }
    final String[] lines = source.split("\n");
    boolean commented = false;
    for (final String line : lines) {
      lc++;

      // the complete line is a comment, so go away
      if (line.trim().startsWith("//")) {
        continue;
      }
      if (line.contains("/*")) { // a comment is starting
        commented = true;
      }
      if (line.contains("*/")) { // comment ends
        commented = false;
      }

      if (lineContains(line, wid) && !commented) {
        return lc;
      }
    }
    return -1;
  }

  /** check if resource is in an source folder */
  private boolean isSource(final IResource resource) {
    if (resource == null || resource.getFullPath() == null) {
      return false;
    }
    final String ps = resource.getFullPath().toPortableString();
    for (final IPath srcFolder : srcFolders) {
      if (ps.startsWith(srcFolder.toPortableString())) {
        return true;
      }
    }
    return false;
  }

  private void deleteMarkers(final IFile file) {
    if (file == null) {
      return;
    }
    try {
      file.deleteMarkers(MARKER_TYPE, false, IResource.DEPTH_ZERO);
    } catch (final CoreException ce) {
    }
  }

  public void fullBuild(final IProgressMonitor monitor) throws CoreException {
    checkSeverity();
    getProject().accept(new QWickieResourceVisitor());
  }

  protected void incrementalBuild(final IResourceDelta delta, final IProgressMonitor monitor) throws CoreException {
    checkSeverity();
    delta.accept(new QWickieDeltaVisitor());
  }

  public void checkSeverity() {
    String ssever = store.getString(QWickiePreferencePage.SEVERITY);
    if (ssever == null || "".equals(ssever)) {
      ssever = store.getDefaultString(QWickiePreferencePage.SEVERITY);
    }
    try {
      severity = Integer.parseInt(ssever);
    } catch (NumberFormatException nfe) {
      try {
        severity = QWickiePreferencePage.SEVERITIES.valueOf(ssever).ordinal();
      } catch (Exception ex) {
        ssever = store.getDefaultString(QWickiePreferencePage.SEVERITY);
      }
    }
  }

}
TOP

Related Classes of qwickie.builder.QWickieBuilder$QWickieDeltaVisitor

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.