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 */ 017package org.apache.wicket.markup; 018 019import java.util.ArrayList; 020 021import org.apache.wicket.Application; 022import org.apache.wicket.Page; 023import org.apache.wicket.markup.html.form.AutoLabelTagHandler; 024import org.apache.wicket.markup.parser.IMarkupFilter; 025import org.apache.wicket.markup.parser.IXmlPullParser; 026import org.apache.wicket.markup.parser.filter.EnclosureHandler; 027import org.apache.wicket.markup.parser.filter.HeadForceTagIdHandler; 028import org.apache.wicket.markup.parser.filter.HtmlHandler; 029import org.apache.wicket.markup.parser.filter.HtmlHeaderSectionHandler; 030import org.apache.wicket.markup.parser.filter.InlineEnclosureHandler; 031import org.apache.wicket.markup.parser.filter.OpenCloseTagExpander; 032import org.apache.wicket.markup.parser.filter.RelativePathPrefixHandler; 033import org.apache.wicket.markup.parser.filter.StyleAndScriptIdentifier; 034import org.apache.wicket.markup.parser.filter.WicketContainerTagHandler; 035import org.apache.wicket.markup.parser.filter.WicketLinkTagHandler; 036import org.apache.wicket.markup.parser.filter.WicketMessageTagHandler; 037import org.apache.wicket.markup.parser.filter.WicketNamespaceHandler; 038import org.apache.wicket.markup.parser.filter.WicketRemoveTagHandler; 039import org.apache.wicket.markup.parser.filter.WicketTagIdentifier; 040import org.apache.wicket.util.lang.Objects; 041 042/** 043 * This is Wicket's default markup parser. It gets pre-configured with Wicket's default wicket 044 * filters. 045 * 046 * @see MarkupFactory 047 * 048 * @author Juergen Donnerstag 049 */ 050public class MarkupParser extends AbstractMarkupParser 051{ 052 /** "wicket" */ 053 public final static String WICKET = "wicket"; 054 055 /** 056 * Constructor. 057 * 058 * @param resource 059 * The markup resource (file) 060 */ 061 public MarkupParser(final MarkupResourceStream resource) 062 { 063 super(resource); 064 } 065 066 /** 067 * Constructor. Usually for testing purposes only 068 * 069 * @param markup 070 * The markup resource. 071 */ 072 public MarkupParser(final String markup) 073 { 074 super(markup); 075 } 076 077 /** 078 * Constructor. 079 * 080 * @param xmlParser 081 * The streaming xml parser to read and parse the markup 082 * @param resource 083 * The markup resource (file) 084 */ 085 public MarkupParser(final IXmlPullParser xmlParser, final MarkupResourceStream resource) 086 { 087 super(xmlParser, resource); 088 } 089 090 @Override 091 public MarkupFilterList getMarkupFilters() 092 { 093 return (MarkupFilterList)super.getMarkupFilters(); 094 } 095 096 /** 097 * Add a markup filter 098 * 099 * @param filter 100 * @return true, if successful 101 */ 102 public final boolean add(final IMarkupFilter filter) 103 { 104 return getMarkupFilters().add(filter); 105 } 106 107 /** 108 * Add a markup filter before the 'beforeFilter' 109 * 110 * @param filter 111 * @param beforeFilter 112 * @return true, if successful 113 */ 114 public final boolean add(final IMarkupFilter filter, 115 final Class<? extends IMarkupFilter> beforeFilter) 116 { 117 return getMarkupFilters().add(filter, beforeFilter); 118 } 119 120 /** 121 * a) Allow subclasses to configure individual Wicket filters 122 * <p> 123 * b) Allows to disable Wicket filters via returning false 124 * 125 * @param filter 126 * @return The filter to be added. Null to ignore. 127 */ 128 protected IMarkupFilter onAppendMarkupFilter(final IMarkupFilter filter) 129 { 130 return filter; 131 } 132 133 /** 134 * Initialize Wicket's MarkupParser with all necessary markup filters. You may subclass this 135 * method, to add your own filters to the list. 136 * 137 * @param markup 138 * @return The list of markup filter 139 */ 140 @Override 141 protected MarkupFilterList initializeMarkupFilters(final Markup markup) 142 { 143 // MarkupFilterList is a simple extension of ArrayList providing few additional helpers 144 final MarkupFilterList filters = new MarkupFilterList(); 145 146 MarkupResourceStream markupResourceStream = markup.getMarkupResourceStream(); 147 148 filters.add(new WicketTagIdentifier(markupResourceStream)); 149 filters.add(new HtmlHandler()); 150 filters.add(new WicketRemoveTagHandler(markupResourceStream)); 151 filters.add(new WicketLinkTagHandler(markupResourceStream)); 152 filters.add(new AutoLabelTagHandler(markupResourceStream)); 153 filters.add(new WicketNamespaceHandler(markupResourceStream)); 154 filters.add(new WicketMessageTagHandler(markupResourceStream)); 155 156 // Provided the wicket component requesting the markup is known ... 157 if ((markupResourceStream != null) && (markupResourceStream.getResource() != null)) 158 { 159 final ContainerInfo containerInfo = markupResourceStream.getContainerInfo(); 160 if (containerInfo != null) 161 { 162 // Pages require additional handlers 163 if (Page.class.isAssignableFrom(containerInfo.getContainerClass())) 164 { 165 filters.add(new HtmlHeaderSectionHandler(markup)); 166 } 167 168 filters.add(new HeadForceTagIdHandler(containerInfo.getContainerClass())); 169 } 170 } 171 172 filters.add(new OpenCloseTagExpander()); 173 filters.add(new RelativePathPrefixHandler(markupResourceStream)); 174 filters.add(new EnclosureHandler(markupResourceStream)); 175 filters.add(new InlineEnclosureHandler(markupResourceStream)); 176 177 // Append it. See WICKET-4390 178 filters.add(new StyleAndScriptIdentifier(), StyleAndScriptIdentifier.class); 179 filters.add(new WicketContainerTagHandler(markupResourceStream, Application.get().usesDevelopmentConfig())); 180 181 return filters; 182 } 183 184 /** 185 * A simple extension to ArrayList to manage Wicket MarkupFilter's more easily 186 */ 187 public class MarkupFilterList extends ArrayList<IMarkupFilter> 188 { 189 private static final long serialVersionUID = 1L; 190 191 @Override 192 public boolean add(final IMarkupFilter filter) 193 { 194 return add(filter, RelativePathPrefixHandler.class); 195 } 196 197 /** 198 * Insert a markup filter before a another one. 199 * 200 * @param filter 201 * @param beforeFilter 202 * @return true, if successful 203 */ 204 public boolean add(IMarkupFilter filter, final Class<? extends IMarkupFilter> beforeFilter) 205 { 206 filter = onAdd(filter); 207 if (filter == null) 208 { 209 return false; 210 } 211 212 int index = firstIndexOfClass(beforeFilter); 213 if (index < 0) 214 { 215 return super.add(filter); 216 } 217 218 super.add(index, filter); 219 return true; 220 } 221 222 /** 223 * Finds the index of the first entry which is from the same type as the passed 224 * {@literal filterClass} argument. 225 * 226 * @param filterClass 227 * the class to search for 228 * @return the index of the first match or -1 otherwise 229 */ 230 private int firstIndexOfClass(final Class<? extends IMarkupFilter> filterClass) 231 { 232 int result = -1; 233 if (filterClass != null) 234 { 235 final int size = size(); 236 for (int index = 0; index < size; index++) { 237 Class<? extends IMarkupFilter> currentFilterClass = get(index).getClass(); 238 if (Objects.equal(filterClass, currentFilterClass)) 239 { 240 result = index; 241 break; 242 } 243 } 244 } 245 return result; 246 } 247 248 /** 249 * a) Allow subclasses to configure individual Wicket filters which otherwise can not be 250 * accessed. 251 * <p> 252 * b) Allows to disable Wicket filters via returning false 253 * 254 * @param filter 255 * @return The filter to be added. Null to ignore 256 */ 257 protected IMarkupFilter onAdd(final IMarkupFilter filter) 258 { 259 return onAppendMarkupFilter(filter); 260 } 261 } 262}