001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017: package org.apache.wicket.markup.parser.filter;
018:
019: import java.text.ParseException;
020: import java.util.Iterator;
021:
022: import org.apache.wicket.markup.ComponentTag;
023: import org.apache.wicket.markup.MarkupElement;
024: import org.apache.wicket.markup.parser.AbstractMarkupFilter;
025: import org.slf4j.Logger;
026: import org.slf4j.LoggerFactory;
027:
028: /**
029: * This is a markup inline filter which by default is not added to the list of
030: * markup filter. It can be added by means of subclassing
031: * Application.newMarkupParser() like
032: *
033: * <pre>
034: * public class MyApplication extends Application
035: * {
036: * ...
037: * public IMarkupFilter[] getAdditionalMarkupHandler()
038: * {
039: * return new IMarkupFilter[] { new HtmlProblemFinder(HtmlProblemFinder.ERR_THROW_EXCEPTION) };
040: * }
041: * </pre>
042: *
043: * The purpose of the filter is to find possible HTML issues and to log a
044: * warning.
045: *
046: * @author Juergen Donnerstag
047: */
048: public final class HtmlProblemFinder extends AbstractMarkupFilter {
049: /** Logging */
050: private static final Logger log = LoggerFactory
051: .getLogger(HtmlProblemFinder.class);
052:
053: /** Ignore the issue detected */
054: public static final int ERR_INGORE = 3;
055:
056: /** Log a warning on the issue detected */
057: public static final int ERR_LOG_WARN = 2;
058:
059: /** Log an error on the issue detected */
060: public static final int ERR_LOG_ERROR = 1;
061:
062: /** Throw an exception on the issue detected */
063: public static final int ERR_THROW_EXCEPTION = 0;
064:
065: /** Default behavior in case of a potential HTML issue detected */
066: private final int problemEscalation;
067:
068: /**
069: * Construct.
070: *
071: * @param problemEscalation
072: * How to escalate the issue found.
073: */
074: public HtmlProblemFinder(final int problemEscalation) {
075: this .problemEscalation = problemEscalation;
076: }
077:
078: /**
079: * Get the next MarkupElement from the parent MarkupFilter and handle it if
080: * the specific filter criteria are met. Depending on the filter, it may
081: * return the MarkupElement unchanged, modified or it remove by asking the
082: * parent handler for the next tag.
083: *
084: * @see org.apache.wicket.markup.parser.IMarkupFilter#nextTag()
085: * @return Return the next eligible MarkupElement
086: */
087: public MarkupElement nextTag() throws ParseException {
088: // Get the next tag. If null, no more tags are available
089: final ComponentTag tag = (ComponentTag) getParent().nextTag();
090: if (tag == null) {
091: return tag;
092: }
093:
094: // Make sure some typical and may be tricky problems are detected and
095: // logged.
096: if ("img".equals(tag.getName())
097: && (tag.isOpen() || tag.isOpenClose())) {
098: String src = tag.getAttributes().getString("src");
099: if ((src != null) && (src.trim().length() == 0)) {
100: escalateWarning(
101: "Attribute 'src' should not be empty. Location: ",
102: tag);
103: }
104: }
105:
106: // Some people are using a dot "wicket.xxx" instead of a colon
107: // "wicket:xxx"
108: Iterator iter = tag.getAttributes().keySet().iterator();
109: while (iter.hasNext()) {
110: String key = (String) iter.next();
111: if (key != null) {
112: key = key.toLowerCase();
113: if (key.startsWith("wicket.")) {
114: escalateWarning(
115: "You probably want 'wicket:xxx' rather than 'wicket.xxx'. Location: ",
116: tag);
117: }
118: }
119: }
120:
121: return tag;
122: }
123:
124: /**
125: * Handle the issue. Depending the setting either log a warning, an error,
126: * throw an exception or ignore it.
127: *
128: * @param msg
129: * The message
130: * @param tag
131: * The current tag
132: * @throws ParseException
133: */
134: private void escalateWarning(final String msg,
135: final ComponentTag tag) throws ParseException {
136: if (problemEscalation == ERR_LOG_WARN) {
137: log.warn(msg + tag.toUserDebugString());
138: } else if (problemEscalation == ERR_LOG_ERROR) {
139: log.error(msg + tag.toUserDebugString());
140: } else if (problemEscalation == ERR_INGORE) {
141: // no action required
142: } else
143: // if (problemEscalation == ERR_THROW_EXCEPTION)
144: {
145: throw new ParseException(msg + tag.toUserDebugString(), tag
146: .getPos());
147: }
148: }
149: }
|