Coverage Report - com.jcabi.w3c.BaseValidator
 
Classes in this File Line Coverage Branch Coverage Complexity
BaseValidator
55%
20/36
50%
6/12
1.667
 
 1  
 /**
 2  
  * Copyright (c) 2011-2015, jcabi.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the jcabi.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.jcabi.w3c;
 31  
 
 32  
 import com.jcabi.http.Request;
 33  
 import com.jcabi.http.request.JdkRequest;
 34  
 import com.jcabi.log.Logger;
 35  
 import com.jcabi.manifests.Manifests;
 36  
 import com.jcabi.xml.XML;
 37  
 import java.io.ByteArrayOutputStream;
 38  
 import java.io.IOException;
 39  
 import java.net.URI;
 40  
 import java.nio.charset.Charset;
 41  
 import java.util.List;
 42  
 import javax.ws.rs.core.HttpHeaders;
 43  
 import javax.ws.rs.core.MediaType;
 44  
 import javax.ws.rs.core.UriBuilder;
 45  
 import lombok.ToString;
 46  
 import org.apache.commons.io.Charsets;
 47  
 import org.apache.commons.lang3.CharEncoding;
 48  
 import org.apache.http.entity.ContentType;
 49  
 import org.apache.http.entity.mime.MultipartEntityBuilder;
 50  
 
 51  
 /**
 52  
  * Abstract implementation of (X)HTML validator.
 53  
  *
 54  
  * @author Yegor Bugayenko (yegor@tpc2.com)
 55  
  * @version $Id$
 56  
  */
 57  0
 @ToString
 58  4
 class BaseValidator {
 59  
 
 60  
     /**
 61  
      * User agent.
 62  
      */
 63  1
     protected static final String USER_AGENT = String.format(
 64  
         "ReXSL-W3C %s %s %s",
 65  
         Manifests.read("JCabi-Version"),
 66  
         Manifests.read("JCabi-Build"),
 67  
         Manifests.read("JCabi-Date")
 68  
     );
 69  
 
 70  
     /**
 71  
      * Boundary for HTTP POST form data (just some random data).
 72  
      */
 73  
     protected static final String BOUNDARY = "vV9olNqRj00PC4OIlM7";
 74  
 
 75  
     /**
 76  
      * Send request and return response.
 77  
      * @param uri The URI to fetch
 78  
      * @param entity The entity to POST
 79  
      * @return The response
 80  
      */
 81  
     protected final Request request(final String uri, final String entity) {
 82  2
         return new JdkRequest(uri)
 83  
             .method(Request.POST)
 84  
             .body().set(entity).back()
 85  
             .header(HttpHeaders.USER_AGENT, BaseValidator.USER_AGENT)
 86  
             .header(HttpHeaders.ACCEPT, "application/soap+xml")
 87  
             .header(
 88  
                 HttpHeaders.CONTENT_TYPE,
 89  
                 Logger.format(
 90  
                     "%s; boundary=%s",
 91  
                     MediaType.MULTIPART_FORM_DATA,
 92  
                     BaseValidator.BOUNDARY
 93  
                 )
 94  
             );
 95  
     }
 96  
 
 97  
     /**
 98  
      * Convert HTML to HTTP FORM entity.
 99  
      * @param name Name of HTTP form field
 100  
      * @param content The content of it
 101  
      * @param type Media type of it
 102  
      * @return The HTTP post body
 103  
      * @throws IOException if fails
 104  
      */
 105  
     protected final String entity(final String name, final String content,
 106  
         final String type) throws IOException {
 107  2
         final ByteArrayOutputStream baos = new ByteArrayOutputStream();
 108  2
         MultipartEntityBuilder.create()
 109  
             .setStrictMode()
 110  
             .setCharset(Charsets.UTF_8)
 111  
             .setBoundary(BaseValidator.BOUNDARY)
 112  
             .addBinaryBody(
 113  
                 name,
 114  
                 content.getBytes(Charsets.UTF_8),
 115  
                 ContentType.create(type, Charsets.UTF_8),
 116  
                 "file"
 117  
             )
 118  
             .addTextBody("output", "soap12")
 119  
             .build()
 120  
             .writeTo(baos);
 121  2
         return baos.toString(CharEncoding.UTF_8);
 122  
     }
 123  
 
 124  
     /**
 125  
      * Build response from XML.
 126  
      * @param soap The response
 127  
      * @return The validation response just built
 128  
      */
 129  
     protected final ValidationResponse build(final XML soap) {
 130  2
         final DefaultValidationResponse resp = new DefaultValidationResponse(
 131  
             "true".equals(
 132  
                 BaseValidator.textOf(soap.xpath("//m:validity/text()"))
 133  
             ),
 134  
             UriBuilder.fromUri(
 135  
                 BaseValidator.textOf(soap.xpath("//m:checkedby/text()"))
 136  
             ).build(),
 137  
             BaseValidator.textOf(soap.xpath("//m:doctype/text()")),
 138  
             BaseValidator.charset(
 139  
                 BaseValidator.textOf(soap.xpath("//m:charset/text()"))
 140  
             )
 141  
         );
 142  2
         for (final XML node : soap.nodes("//m:error")) {
 143  0
             resp.addError(this.defect(node));
 144  0
         }
 145  2
         for (final XML node : soap.nodes("//m:warning")) {
 146  0
             resp.addWarning(this.defect(node));
 147  0
         }
 148  2
         return resp;
 149  
     }
 150  
 
 151  
     /**
 152  
      * Build response from error that just happened.
 153  
      * @param error The exception
 154  
      * @return The validation response just built
 155  
      */
 156  
     protected final ValidationResponse failure(final Throwable error) {
 157  0
         final DefaultValidationResponse resp = new DefaultValidationResponse(
 158  
             false,
 159  
             URI.create("http://localhost/failure"),
 160  
             "unknown-doctype",
 161  
             Charset.defaultCharset()
 162  
         );
 163  0
         String message = error.getMessage();
 164  0
         if (message == null) {
 165  0
             message = "";
 166  
         }
 167  0
         resp.addError(
 168  
             new Defect(
 169  
                 0,
 170  
                 0,
 171  
                 "",
 172  
                 Logger.format("%[exception]s", error),
 173  
                 "",
 174  
                 message
 175  
             )
 176  
         );
 177  0
         return resp;
 178  
     }
 179  
 
 180  
     /**
 181  
      * Build a success response.
 182  
      * @param type Media type of resource just processed
 183  
      * @return The validation response just built
 184  
      */
 185  
     protected final ValidationResponse success(final String type) {
 186  1
         final DefaultValidationResponse resp = new DefaultValidationResponse(
 187  
             true,
 188  
             URI.create("http://localhost/success"),
 189  
             type,
 190  
             Charset.defaultCharset()
 191  
         );
 192  1
         return resp;
 193  
     }
 194  
 
 195  
     /**
 196  
      * Convert SOAP node to defect.
 197  
      * @param node The node
 198  
      * @return The defect
 199  
      */
 200  
     private Defect defect(final XML node) {
 201  0
         return new Defect(
 202  
             BaseValidator.intOf(node.xpath("m:line/text()")),
 203  
             BaseValidator.intOf(node.xpath("m:col/text()")),
 204  
             BaseValidator.textOf(node.xpath("m:source/text()")),
 205  
             BaseValidator.textOf(node.xpath("m:explanation/text()")),
 206  
             BaseValidator.textOf(node.xpath("m:messageid/text()")),
 207  
             BaseValidator.textOf(node.xpath("m:message/text()"))
 208  
         );
 209  
     }
 210  
 
 211  
     /**
 212  
      * Get text from list of strings, returned by
 213  
      * {@link XML#xpath(String)}.
 214  
      *
 215  
      * <p>This method is required to simplify manipulations with XPath returned
 216  
      * list of strings (returned by {@link XML#xpath(String)} above).
 217  
      * The list of strings normally (!) contains one element or no elements. If
 218  
      * there are no elements it means that the XPath is not found in the
 219  
      * document. In this case we should return an empty string. If any elements
 220  
      * are found - we're interested only in the first one. All others are
 221  
      * ignored, because simply should not exist (if our XPath query is correct).
 222  
      *
 223  
      * @param lines The lines to work with
 224  
      * @return The value
 225  
      * @see #intOf(List)
 226  
      */
 227  
     private static String textOf(final List<String> lines) {
 228  
         final String text;
 229  8
         if (lines.isEmpty()) {
 230  2
             text = "";
 231  
         } else {
 232  6
             text = lines.get(0);
 233  
         }
 234  8
         return text;
 235  
     }
 236  
 
 237  
     /**
 238  
      * Get text from list of strings.
 239  
      *
 240  
      * <p>See explanation of {@link #textOf(List)}.
 241  
      *
 242  
      * @param lines The lines to work with
 243  
      * @return The value
 244  
      * @see #textOf(List)
 245  
      */
 246  
     private static int intOf(final List<String> lines) {
 247  
         final int value;
 248  0
         if (lines.isEmpty()) {
 249  0
             value = 0;
 250  
         } else {
 251  0
             value = Integer.parseInt(lines.get(0));
 252  
         }
 253  0
         return value;
 254  
     }
 255  
 
 256  
     /**
 257  
      * Convert text to charset.
 258  
      * @param text Text representation of charset
 259  
      * @return The charset
 260  
      */
 261  
     private static Charset charset(final String text) {
 262  
         final Charset charset;
 263  2
         if (text.isEmpty()) {
 264  1
             charset = Charset.defaultCharset();
 265  
         } else {
 266  1
             charset = Charset.forName(text);
 267  
         }
 268  2
         return charset;
 269  
     }
 270  
 
 271  
 }