/* * 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.wicket.markup.parser.filter; import java.text.ParseException; import org.apache.wicket.markup.ComponentTag; import org.apache.wicket.markup.MarkupElement; import org.apache.wicket.markup.WicketParseException; import org.apache.wicket.markup.parser.AbstractMarkupFilter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This is a markup inline filter which by default is not added to the list of markup filter. It can * be added by means of subclassing Application.newMarkupParser() like * * <pre> * Application#init() { * getMarkupSettings().setMarkupParserFactory() { * new MarkupParserFactory() { * MarkupParser newMarkupParser(final MarkupResourceStream resource) { * MarkupParser parser=super.newMarkupParser(resource); * parser.appendMarkupFilter(new HtmlProblemFinder(HtmlProblemFinder.ERR_THROW_EXCEPTION)); * return parser; * } * } * } * } * </pre> * * The purpose of the filter is to find possible HTML issues and to log a warning. * * @author Juergen Donnerstag */ public final class HtmlProblemFinder extends AbstractMarkupFilter { /** Logging */ private static final Logger log = LoggerFactory.getLogger(HtmlProblemFinder.class); /** Ignore the issue detected */ public static final int ERR_INGORE = 3; /** Log a warning on the issue detected */ public static final int ERR_LOG_WARN = 2; /** Log an error on the issue detected */ public static final int ERR_LOG_ERROR = 1; /** Throw an exception on the issue detected */ public static final int ERR_THROW_EXCEPTION = 0; /** Default behavior in case of a potential HTML issue detected */ private final int problemEscalation; /** * Construct. * * @param problemEscalation * How to escalate the issue found. */ public HtmlProblemFinder(final int problemEscalation) { this.problemEscalation = problemEscalation; } @Override protected final MarkupElement onComponentTag(ComponentTag tag) throws ParseException { // Make sure some typical and may be tricky problems are detected and // logged. if ("img".equals(tag.getName()) && (tag.isOpen() || tag.isOpenClose())) { String src = tag.getAttributes().getString("src"); if ((src != null) && (src.trim().length() == 0)) { escalateWarning("Attribute 'src' should not be empty. Location: ", tag); } } // Some people are using a dot "wicket.xxx" instead of a colon // "wicket:xxx" for (String key : tag.getAttributes().keySet()) { if (key != null) { key = key.toLowerCase(); String namespaceDot = getWicketNamespace() + '.'; if (key.startsWith(namespaceDot)) { escalateWarning( String.format("You probably want '%s:xxx' rather than '%s.xxx'. Location: ", namespaceDot, namespaceDot), tag); } } } return tag; } /** * Handle the issue. Depending the setting either log a warning, an error, throw an exception or * ignore it. * * @param msg * The message * @param tag * The current tag * @throws WicketParseException */ private void escalateWarning(final String msg, final ComponentTag tag) throws WicketParseException { if (problemEscalation == ERR_LOG_WARN) { log.warn(msg + tag.toUserDebugString()); } else if (problemEscalation == ERR_LOG_ERROR) { log.error(msg + tag.toUserDebugString()); } else if (problemEscalation == ERR_INGORE) { // no action required } else // if (problemEscalation == ERR_THROW_EXCEPTION) { throw new WicketParseException(msg, tag); } } }