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.html.include; 018 019import java.net.MalformedURLException; 020import java.net.URL; 021import java.nio.charset.Charset; 022 023import javax.servlet.ServletContext; 024 025import org.apache.wicket.IGenericComponent; 026import org.apache.wicket.WicketRuntimeException; 027import org.apache.wicket.core.util.resource.UrlResourceStream; 028import org.apache.wicket.markup.ComponentTag; 029import org.apache.wicket.markup.MarkupStream; 030import org.apache.wicket.markup.html.WebComponent; 031import org.apache.wicket.model.IModel; 032import org.apache.wicket.model.Model; 033import org.apache.wicket.request.UrlUtils; 034import org.apache.wicket.resource.ResourceUtil; 035import org.apache.wicket.util.lang.Args; 036 037 038/** 039 * <p> 040 * Component that includes/ renders the import result of an URL, much like JSP include. 041 * </p> 042 * <p> 043 * Use this to integrate non-Wicket locations in your page. <strong>This component is NOT meant for 044 * integrating more Wicket sources as a means of quick and dirty page composition. Use Panels, 045 * Borders and (Markup)inheritance for page composition instead.</strong> 046 * </p> 047 * <p> 048 * You can feed this component the URL directly, or use a model that should deliver a valid URL. You 049 * can both use absolute (e.g. http://www.theserverside.com/) and relative (e.g. mydir/mypage.html) 050 * urls. This component will try to resolve relative urls to resources in the same webapplication. 051 * </p> 052 * <p> 053 * The following example shows how to integrate a header and footer, coming from a plain HTML source 054 * on the same server is integrated using this component. The files footer.html and header.html 055 * would be located in the web application root directory 056 * </p> 057 * <p> 058 * Java: 059 * 060 * <pre> 061 * ... 062 * add(new Include("header", "header.html")); 063 * add(new Include("footer", "footer.html")); 064 * ... 065 * </pre> 066 * 067 * Html: 068 * 069 * <pre> 070 * ... 071 * <div> 072 * <div wicket:id="header">header comes here</div> 073 * <div>I am the body!</div> 074 * <div wicket:id="footer">footer comes here</div> 075 * </div> 076 * ... 077 * </pre> 078 * 079 * </p> 080 * 081 * @author Eelco Hillenius 082 */ 083public class Include extends WebComponent implements IGenericComponent<String, Include> 084{ 085 private static final long serialVersionUID = 1L; 086 087 /** 088 * Construct. 089 * 090 * @param id 091 * component id 092 */ 093 public Include(final String id) 094 { 095 super(id); 096 } 097 098 /** 099 * Construct. 100 * 101 * @param id 102 * component id 103 * @param model 104 * the model 105 */ 106 public Include(String id, IModel<String> model) 107 { 108 super(id, model); 109 } 110 111 /** 112 * Construct. 113 * 114 * @param id 115 * component id 116 * @param modelObject 117 * the model object (will be wrapped in a model) 118 */ 119 public Include(String id, String modelObject) 120 { 121 super(id, new Model<>(modelObject)); 122 } 123 124 /** 125 * Imports the contents of the url of the model object. 126 * 127 * @return the imported contents 128 */ 129 protected String importAsString() 130 { 131 // gets the model object: should provide us with either an absolute or a 132 // relative url 133 String url = getModelObject(); 134 135 if (UrlUtils.isRelative(url)) 136 { 137 return importRelativeUrl(url); 138 } 139 else 140 { 141 return importAbsoluteUrl(url); 142 } 143 } 144 145 @Override 146 public void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) 147 { 148 String content = importAsString(); 149 replaceComponentTagBody(markupStream, openTag, content); 150 } 151 152 /** 153 * Imports from a relative url. 154 * 155 * @param url 156 * the url to import 157 * @return the imported url's contents 158 */ 159 private String importRelativeUrl(String url) 160 { 161 Args.notEmpty(url, "url"); 162 163 if (url.charAt(0) != '/') 164 { 165 url = '/' + url; 166 } 167 168 try 169 { 170 ServletContext servletContext = getWebApplication().getServletContext(); 171 URL resource = servletContext.getResource(url); 172 return importUrl(resource); 173 } catch (MalformedURLException mux) 174 { 175 throw new WicketRuntimeException(mux); 176 } 177 } 178 179 /** 180 * Imports from an absolute url. 181 * 182 * @param url 183 * the url to import 184 * @return the imported url's contents 185 */ 186 private String importAbsoluteUrl(CharSequence url) 187 { 188 try 189 { 190 return importUrl(new URL(url.toString())); 191 } 192 catch (MalformedURLException e) 193 { 194 throw new WicketRuntimeException(e); 195 } 196 } 197 198 /** 199 * 200 * @return The charset of the text to be retrieved and included 201 */ 202 public Charset getCharset() 203 { 204 return null; 205 } 206 207 /** 208 * Imports the contents from the given url. 209 * 210 * @param url 211 * the url 212 * @return the imported contents 213 */ 214 private String importUrl(URL url) 215 { 216 return ResourceUtil.readString(new UrlResourceStream(url), getCharset()); 217 } 218}