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.loader; 018 019import java.io.IOException; 020 021import org.apache.wicket.MarkupContainer; 022import org.apache.wicket.markup.IMarkupFragment; 023import org.apache.wicket.markup.Markup; 024import org.apache.wicket.markup.MarkupFactory; 025import org.apache.wicket.markup.MarkupNotFoundException; 026import org.apache.wicket.markup.MarkupResourceStream; 027import org.apache.wicket.markup.MergedMarkup; 028import org.apache.wicket.markup.TagUtils; 029import org.apache.wicket.util.resource.ResourceStreamNotFoundException; 030import org.apache.wicket.core.util.resource.locator.ResourceStreamLocator; 031 032/** 033 * Merge the 2+ markups involved in markup inheritance. From a users perspective there is only one 034 * markup associated with the component, the merged one. 035 * 036 * @author Juergen Donnerstag 037 */ 038public class InheritedMarkupMarkupLoader implements IMarkupLoader 039{ 040 /** 041 * Constructor. 042 */ 043 public InheritedMarkupMarkupLoader() 044 { 045 } 046 047 /** 048 * Load the markup from the resource stream with the base MarkupLoader provided, than check if 049 * markup inheritance must be applied. If yes, than load the base markup and merge them. 050 */ 051 @Override 052 public final Markup loadMarkup(final MarkupContainer container, 053 final MarkupResourceStream markupResourceStream, final IMarkupLoader baseLoader, 054 final boolean enforceReload) throws IOException, ResourceStreamNotFoundException 055 { 056 // read and parse the markup 057 Markup markup = baseLoader.loadMarkup(container, markupResourceStream, null, enforceReload); 058 059 // Check if markup contains <wicket:extend> which tells us that 060 // we need to read the inherited markup as well. 061 int extendIndex = requiresBaseMarkup(markup); 062 if (extendIndex == -1) 063 { 064 return markup; 065 } 066 067 // Load the base markup 068 final Markup baseMarkup = getBaseMarkup(container, markup, enforceReload); 069 if ((baseMarkup == null) || (baseMarkup == Markup.NO_MARKUP)) 070 { 071 throw new MarkupNotFoundException( 072 "Base markup of inherited markup not found. Component class: " + 073 markup.getMarkupResourceStream() 074 .getContainerInfo() 075 .getContainerClass() 076 .getName() + 077 ". Enable debug messages for " + ResourceStreamLocator.class.getName() + 078 " to get a list of all filenames tried."); 079 } 080 081 // Merge base and derived markup 082 return new MergedMarkup(markup, baseMarkup, extendIndex); 083 } 084 085 /** 086 * Load the base markup 087 * 088 * @param container 089 * @param markup 090 * @param enforceReload 091 * @return the base markup 092 */ 093 private Markup getBaseMarkup(final MarkupContainer container, final Markup markup, 094 final boolean enforceReload) 095 { 096 final Class<?> location = markup.getMarkupResourceStream().getMarkupClass().getSuperclass(); 097 098 // get the base markup 099 return MarkupFactory.get().getMarkup(container, location, enforceReload); 100 } 101 102 /** 103 * Check if markup contains <wicket:extend> which tells us that we need to read the 104 * inherited markup as well. <wicket:extend> MUST BE the first wicket tag in the markup. 105 * Skip raw markup 106 * 107 * @param markup 108 * @return == 0, if no wicket:extend was found 109 */ 110 private int requiresBaseMarkup(final IMarkupFragment markup) 111 { 112 for (int i = 0; i < markup.size(); i++) 113 { 114 if (TagUtils.isExtendTag(markup, i)) 115 { 116 // Ok, inheritance is on and we must get the 117 // inherited markup as well. 118 return i; 119 } 120 } 121 return -1; 122 } 123}