| /* |
| * 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 org.netbeans.modules.html.validation; |
| |
| import java.io.IOException; |
| import java.io.StringWriter; |
| import java.io.Writer; |
| import nu.validator.htmlparser.sax.HtmlSerializer; |
| import nu.validator.messages.MessageEmitter; |
| import nu.validator.messages.MessageTextHandler; |
| import nu.validator.messages.ResultHandler; |
| import nu.validator.messages.TextMessageTextHandler; |
| import nu.validator.messages.types.MessageType; |
| import nu.validator.source.SourceHandler; |
| import org.netbeans.modules.html.editor.lib.api.ProblemDescription; |
| import org.xml.sax.Attributes; |
| import org.xml.sax.ContentHandler; |
| import org.xml.sax.Locator; |
| |
| import org.xml.sax.SAXException; |
| |
| /** |
| * This is netbeans implementation of MessageEmitter |
| */ |
| public class NbMessageEmitter extends MessageEmitter { |
| |
| private static final char[] COLON_SPACE = { ':', ' ' }; |
| |
| private static final char[] PERIOD = { '.' }; |
| |
| private static final char[] ON_LINE = "On line ".toCharArray(); |
| |
| private static final char[] AT_LINE = "At line ".toCharArray(); |
| |
| private static final char[] FROM_LINE = "From line ".toCharArray(); |
| |
| private static final char[] TO_LINE = "; to line ".toCharArray(); |
| |
| private static final char[] COLUMN = ", column ".toCharArray(); |
| |
| private static final char[] IN_RESOURCE = " in resource ".toCharArray(); |
| |
| private TextMessageTextHandler messageTextHandler; |
| |
| private String systemId; |
| |
| private int oneBasedFirstLine; |
| |
| private int oneBasedFirstColumn; |
| |
| private int oneBasedLastLine; |
| |
| private int oneBasedLastColumn; |
| |
| private boolean textEmitted; |
| |
| private HtmlSerializer contentHandler; |
| |
| private ProblemsHandler problemsHandler; |
| |
| private int problemType; |
| |
| private LinesMapper linesMapper; |
| |
| private Writer writer; |
| |
| private boolean asciiQuotes; |
| |
| private ContentHandler elaborationContentHandler; |
| |
| // private static Writer newOutputStreamWriter(OutputStream out) { |
| // CharsetEncoder enc = Charset.forName("UTF-8").newEncoder(); |
| // enc.onMalformedInput(CodingErrorAction.REPLACE); |
| // enc.onUnmappableCharacter(CodingErrorAction.REPLACE); |
| // return new OutputStreamWriter(out, enc); |
| // } |
| |
| public NbMessageEmitter(ProblemsHandler problemsHandler, LinesMapper linesMapper, boolean asciiQuotes) { |
| this.problemsHandler = problemsHandler; |
| this.linesMapper = linesMapper; |
| this.asciiQuotes = asciiQuotes; |
| } |
| |
| private void emitErrorLevel(char[] level) throws IOException { |
| writer.write(level, 0, level.length); |
| } |
| |
| private void maybeEmitLocation() throws IOException { |
| if (oneBasedLastLine == -1 && systemId == null) { |
| return; |
| } |
| if (oneBasedLastLine == -1) { |
| emitSystemId(); |
| } else if (oneBasedLastColumn == -1) { |
| emitLineLocation(); |
| } else if (oneBasedFirstLine == -1 |
| || (oneBasedFirstLine == oneBasedLastLine && oneBasedFirstColumn == oneBasedLastColumn)) { |
| emitSingleLocation(); |
| } else { |
| emitRangeLocation(); |
| } |
| writer.write('\n'); |
| } |
| |
| /** |
| * @throws SAXException |
| */ |
| private void maybeEmitInResource() throws IOException { |
| if (systemId != null) { |
| this.writer.write(IN_RESOURCE); |
| emitSystemId(); |
| } |
| } |
| |
| /** |
| * @throws SAXException |
| */ |
| private void emitSystemId() throws IOException { |
| this.writer.write(systemId); |
| } |
| |
| private void emitRangeLocation() throws IOException { |
| this.writer.write(FROM_LINE); |
| this.writer.write(Integer.toString(oneBasedFirstLine)); |
| this.writer.write(COLUMN); |
| this.writer.write(Integer.toString(oneBasedFirstColumn)); |
| this.writer.write(TO_LINE); |
| this.writer.write(Integer.toString(oneBasedLastLine)); |
| this.writer.write(COLUMN); |
| this.writer.write(Integer.toString(oneBasedLastColumn)); |
| maybeEmitInResource(); |
| } |
| |
| private void emitSingleLocation() throws IOException { |
| this.writer.write(AT_LINE); |
| this.writer.write(Integer.toString(oneBasedLastLine)); |
| this.writer.write(COLUMN); |
| this.writer.write(Integer.toString(oneBasedLastColumn)); |
| maybeEmitInResource(); |
| } |
| |
| private void emitLineLocation() throws IOException { |
| this.writer.write(ON_LINE); |
| this.writer.write(Integer.toString(oneBasedLastLine)); |
| maybeEmitInResource(); |
| } |
| |
| @Override |
| public void startMessage(MessageType type, String systemId, |
| int oneBasedFirstLine, int oneBasedFirstColumn, |
| int oneBasedLastLine, int oneBasedLastColumn, boolean exact) |
| throws SAXException { |
| |
| this.writer = new StringWriter(); |
| this.elaborationContentHandler = new SimplifiedMessagesContentHandler(writer); |
| this.messageTextHandler = new TextMessageTextHandler(writer, asciiQuotes); |
| this.contentHandler = new HtmlSerializer(writer); |
| |
| |
| this.systemId = systemId; |
| this.oneBasedFirstLine = oneBasedFirstLine; |
| this.oneBasedFirstColumn = oneBasedFirstColumn; |
| this.oneBasedLastLine = oneBasedLastLine; |
| this.oneBasedLastColumn = oneBasedLastColumn; |
| try { |
| emitErrorLevel(type.getPresentationName()); |
| } catch (IOException e) { |
| throw new SAXException(e.getMessage(), e); |
| } |
| this.textEmitted = false; |
| |
| problemType = messageTypeToProblemType(type); |
| } |
| |
| private static int messageTypeToProblemType(MessageType type) { |
| if(type == MessageType.INFO) { |
| return ProblemDescription.INFORMATION; |
| } else if(type == MessageType.WARNING) { |
| return ProblemDescription.WARNING; |
| } else if(type == MessageType.FATAL) { |
| return ProblemDescription.FATAL; |
| } else if(type == MessageType.INTERNAL) { |
| return ProblemDescription.INTERNAL_ERROR; |
| } else { |
| return ProblemDescription.ERROR; |
| } |
| } |
| |
| /** |
| * @see nu.validator.messages.MessageEmitter#startMessages(java.lang.String) |
| */ |
| @Override |
| public void startMessages(String documentUri, boolean willShowSource) throws SAXException { |
| problemsHandler.startProblems(); |
| } |
| |
| /** |
| * @see nu.validator.messages.MessageEmitter#endMessages() |
| */ |
| @Override |
| public void endMessages() throws SAXException { |
| problemsHandler.endProblems(); |
| } |
| |
| /** |
| * @see nu.validator.messages.MessageEmitter#endText() |
| */ |
| @Override |
| public void endText() throws SAXException { |
| try { |
| this.writer.write('\n'); |
| this.textEmitted = true; |
| } catch (IOException e) { |
| throw new SAXException(e.getMessage(), e); |
| } |
| |
| } |
| |
| |
| /** |
| * @see nu.validator.messages.MessageEmitter#startText() |
| */ |
| @Override |
| public MessageTextHandler startText() throws SAXException { |
| try { |
| this.writer.write(COLON_SPACE); |
| return messageTextHandler; |
| } catch (IOException e) { |
| throw new SAXException(e.getMessage(), e); |
| } |
| } |
| |
| @Override |
| public void endMessage() throws SAXException { |
| try { |
| if (!textEmitted) { |
| writer.write(PERIOD); |
| writer.write('\n'); |
| } |
| maybeEmitLocation(); |
| writer.write('\n'); |
| } catch (IOException e) { |
| throw new SAXException(e.getMessage(), e); |
| } |
| |
| int from, to; |
| if(oneBasedFirstLine == -1) { |
| //no position at all - use first line |
| from = 0; |
| to = linesMapper.getLinesCount() > 0 ? linesMapper.getLine(0).getEnd() : 0; |
| |
| } else { |
| int linefrom = -1, lineto = -1, columnfrom = -1, columnto = -1; |
| if (oneBasedFirstLine != -1) { |
| linefrom = oneBasedFirstLine; |
| columnfrom = oneBasedFirstColumn == -1 ? 0 : oneBasedFirstColumn; |
| } |
| if (oneBasedLastLine != -1) { |
| lineto = oneBasedLastLine; |
| columnto = oneBasedLastColumn == -1 ? 0 : oneBasedLastColumn; |
| } else { |
| lineto = linefrom; |
| columnto = 1; |
| } |
| |
| from = linesMapper.getSourceOffsetForLocation(linefrom - 1, columnfrom - 1); |
| to = linesMapper.getSourceOffsetForLocation(lineto - 1, columnto); |
| } |
| |
| problemsHandler.addProblem(ProblemDescription.create("nu.validator.issue", |
| writer.toString(), |
| problemType, |
| from, |
| to)); |
| |
| |
| } |
| |
| /** |
| * @see nu.validator.messages.MessageEmitter#startResult() |
| */ |
| @Override |
| public ResultHandler startResult() throws SAXException { |
| return null; |
| } |
| |
| @Override |
| public ContentHandler startElaboration() throws SAXException { |
| return elaborationContentHandler; |
| } |
| |
| @Override |
| public SourceHandler startFullSource(int lineOffset) throws SAXException { |
| return super.startFullSource(lineOffset); |
| } |
| |
| @Override |
| public SourceHandler startSource() throws SAXException { |
| return super.startSource(); |
| } |
| |
| private static class SimplifiedMessagesContentHandler implements ContentHandler { |
| |
| private static boolean inDD, inDL, inDT, inCODE; |
| private Writer out; |
| |
| private static final String DL = "dl"; |
| private static final String DT = "dt"; |
| private static final String DD = "dd"; |
| private static final String CODE = "code"; |
| |
| public SimplifiedMessagesContentHandler(Writer out) { |
| this.out = out; |
| } |
| |
| private void write(String s) throws SAXException { |
| try { |
| out.write(s); |
| } catch (IOException ex) { |
| throw new SAXException(ex); |
| } |
| } |
| |
| public void setDocumentLocator(Locator locator) { |
| } |
| |
| public void startDocument() throws SAXException { |
| inDD = false; |
| inDT = false; |
| inDL = false; |
| inCODE = false; |
| |
| write("\n"); |
| } |
| |
| public void endDocument() throws SAXException { |
| } |
| |
| public void startPrefixMapping(String prefix, String uri) throws SAXException { |
| } |
| |
| public void endPrefixMapping(String prefix) throws SAXException { |
| } |
| |
| public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { |
| if(DL.equals(localName)) { |
| inDL = true; |
| } else if (DT.equals(localName)) { |
| inDT = true; |
| } else if(DD.equals(localName)) { |
| inDD = true; |
| } else if(CODE.equals(localName)) { |
| inCODE = true; |
| write("'"); |
| } |
| } |
| |
| public void endElement(String uri, String localName, String qName) throws SAXException { |
| if(DL.equals(localName)) { |
| inDL = false; |
| } else if (DT.equals(localName)) { |
| inDT = false; |
| write("\n"); |
| } else if(DD.equals(localName)) { |
| inDD = false; |
| write("\n"); |
| } else if(CODE.equals(localName)) { |
| inCODE = false; |
| write("'"); |
| } |
| } |
| |
| public void characters(char[] ch, int start, int length) throws SAXException { |
| if(inDL) { |
| if(inDD || inDT || inCODE) { |
| write(new String(ch, start, length)); |
| } |
| } |
| } |
| |
| public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { |
| } |
| |
| public void processingInstruction(String target, String data) throws SAXException { |
| } |
| |
| public void skippedEntity(String name) throws SAXException { |
| } |
| |
| } |
| |
| |
| } |