Java tutorial
/* * 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.apache.struts.maven.snippetextractor.parser; import org.apache.struts.maven.snippetextractor.parser.java.InvalidSnippetException; import java.util.regex.Matcher; import java.util.regex.Pattern; import static org.apache.commons.lang.StringUtils.isBlank; /** * Parser handling the logic for finding start, name and end of a snippet. * </p> * The pattern for a snippet start is: {@code <!-- START SNIPPET: snippet name -->}. * </p> * The pattern for a snippet end is : {@code <!-- END SNIPPET: snippet name -->}. * </p> * Every snippet must have a name. You cannot nest snippets. * </p> * The snippet start and end can be escaped with a double backslash: {@literal \\}. */ public class SnippetParser { private static final String SNIPPET_START_REGEX = "(?<!\\\\)(<!--\\s*START SNIPPET:)(.*?)(-->)"; private static final Pattern SNIPPET_START_PATTERN = Pattern.compile(SNIPPET_START_REGEX); private static final String SNIPPET_STOP_REGEX = "(?<!\\\\)(<!--\\s*END SNIPPET:)(.*?)(-->)"; private static final Pattern SNIPPET_END_PATTERN = Pattern.compile(SNIPPET_STOP_REGEX); private String snippetName = null; private Matcher snippetStartMatcher; private Matcher snippetEndMatcher; /** * Constructor for a statefull SnippetParser. Before making the effort to instantiate one, check if there is a * snippet start in your string using the static method {@link #isSnippetStart(String)}. As every snippet must have * a name a {@link InvalidSnippetException} will be thrown if there is a unnamed snippet. * * @param string containing the snippet start to be parsed * @throws IllegalArgumentException if you provide a string without a snippet start, * use {@link #isSnippetStart(String)} before * @throws InvalidSnippetException if the snippet is unnamed */ public SnippetParser(String string) throws IllegalArgumentException, InvalidSnippetException { snippetStartMatcher = SNIPPET_START_PATTERN.matcher(string); if (isSnippetStart(string, snippetStartMatcher)) { snippetName = snippetStartMatcher.group(2); } if (snippetName == null) { throw new IllegalArgumentException( "No snippet found. Use isSnippetStart first before creating instance."); } snippetName = snippetName.trim(); if (isBlank(snippetName)) { throw new InvalidSnippetException("Snippet without name found. This is an invalid snippet."); } } /** * Check wether the provided string contains a snippet start which should look like * {@code <!-- START SNIPPET: snippet name -->}. * * @param string to be parsed for a snippet start * @return {@code true} if a snippet start is found, otherwise {@code false} */ public static boolean isSnippetStart(String string) { return isSnippetStart(string, null); } private static boolean isSnippetStart(String string, Matcher matcher) { if (matcher == null) { matcher = SNIPPET_START_PATTERN.matcher(string); } return matcher.find() && matcher.groupCount() == 3; } /** * Get the name of the snippet the SnippetParser was instantiated with. * * @return snippet name without surrounding whitespaces */ public String getSnippetName() { return snippetName; } /** * Get the complete snippet start string without any clutter that is not part of the snippet start pattern. * * @return complete snippet start */ public String getSnippetStart() { return snippetStartMatcher.group(); } /** * Checks whether the provided string contains a matching snippet end pattern for this snippet. A snippet end looks * like {@code <!-- END SNIPPET: snippet name -->}. The name must match to the snippet start, otherwise a * {@link InvalidSnippetException} is thrown. * * @param string to parse for a matching snippet end * @return {@code true} if a matching snippet is found, otherwise {@code false} * @throws InvalidSnippetException is thrown if the name of the snippet end does not match the name the snippet * start this SnippetParser was instatiated with. */ public boolean isSnippetEnd(String string) throws InvalidSnippetException { snippetEndMatcher = SNIPPET_END_PATTERN.matcher(string); if (!doesContainSnippetEnd(snippetEndMatcher)) { snippetEndMatcher = null; return false; } String snippetEndName = snippetEndMatcher.group(2).trim(); if (!snippetName.equals(snippetEndName)) { snippetEndMatcher = null; throw new InvalidSnippetException("End of snippet with name " + snippetEndName + " found, but " + "snippet " + snippetName + " still open. Cannot handle nested snippets."); } return true; } /** * Get the index of where the snippet end starts. Be sure you have looked for the snippet end before with the method * {@link #isSnippetEnd(String)}, otherwise a {@link IllegalStateException} will be thrown. * * @return position where the snippet end pattern starts * @throws IllegalStateException if {@link #isSnippetEnd(String)} was not called before once */ public int indexOfSnippetEnd() throws IllegalStateException { if (snippetEndMatcher == null) { throw new IllegalStateException( "Snippet end not yet found. Use isSnippetEnd() for finding it before " + "using this method."); } return snippetEndMatcher.start(); } private boolean doesContainSnippetEnd(Matcher matcher) { return matcher.find() && matcher.groupCount() == 3; } }