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.transformer; 018 019import org.apache.wicket.Component; 020import org.apache.wicket.MarkupContainer; 021import org.apache.wicket.WicketRuntimeException; 022import org.apache.wicket.markup.ComponentTag; 023import org.apache.wicket.markup.MarkupStream; 024import org.apache.wicket.model.IModel; 025import org.apache.wicket.request.Response; 026import org.apache.wicket.response.StringResponse; 027 028/** 029 * This abstract container provides the means to post-process the markup generated by its child 030 * components (excluding the containers tag) 031 * <p> 032 * Please see {@link org.apache.wicket.markup.transformer.AbstractTransformerBehavior} for an alternative 033 * based on {@link org.apache.wicket.behavior.Behavior} 034 * 035 * @see org.apache.wicket.markup.transformer.AbstractTransformerBehavior 036 * @see org.apache.wicket.markup.transformer.ITransformer 037 * 038 * @author Juergen Donnerstag 039 * */ 040public abstract class AbstractOutputTransformerContainer extends MarkupContainer 041 implements 042 ITransformer 043{ 044 private static final long serialVersionUID = 1L; 045 046 /** Whether the containers tag shall be transformed as well */ 047 private boolean transformBodyOnly = true; 048 049 /** 050 * Construct 051 * 052 * @see org.apache.wicket.Component#Component(String) 053 */ 054 public AbstractOutputTransformerContainer(final String id) 055 { 056 super(id); 057 } 058 059 /** 060 * Construct 061 * 062 * @see org.apache.wicket.Component#Component(String, IModel) 063 */ 064 public AbstractOutputTransformerContainer(final String id, final IModel<?> model) 065 { 066 super(id, model); 067 } 068 069 /** 070 * You can choose whether the body of the tag excluding the tag shall be transformed or 071 * including the tag. 072 * 073 * @param value 074 * If true, only the body is applied to transformation. 075 * @return this 076 */ 077 public MarkupContainer setTransformBodyOnly(final boolean value) 078 { 079 transformBodyOnly = value; 080 return this; 081 } 082 083 /** 084 * Create a new response object which is used to store the markup generated by the child 085 * objects. 086 * 087 * @return Response object. Must not be null 088 */ 089 protected Response newResponse() 090 { 091 return new StringResponse(); 092 } 093 094 @Override 095 public abstract CharSequence transform(final Component component, final CharSequence output) 096 throws Exception; 097 098 @Override 099 public final void onComponentTagBody(final MarkupStream markupStream, final ComponentTag openTag) 100 { 101 if (transformBodyOnly == true) 102 { 103 execute(new Runnable() 104 { 105 @Override 106 public void run() 107 { 108 // Invoke default execution 109 AbstractOutputTransformerContainer.super.onComponentTagBody(markupStream, 110 openTag); 111 } 112 }); 113 } 114 else 115 { 116 super.onComponentTagBody(markupStream, openTag); 117 } 118 } 119 120 @Override 121 protected final void onRender() 122 { 123 if (transformBodyOnly == false) 124 { 125 execute(new Runnable() 126 { 127 @Override 128 public void run() 129 { 130 // Invoke default execution 131 AbstractOutputTransformerContainer.super.onRender(); 132 } 133 }); 134 } 135 else 136 { 137 super.onRender(); 138 } 139 } 140 141 /** 142 * 143 * @param code 144 */ 145 private void execute(final Runnable code) 146 { 147 // Temporarily replace the web response with a String response 148 final Response webResponse = getResponse(); 149 150 try 151 { 152 // Create a new response object 153 final Response response = newResponse(); 154 if (response == null) 155 { 156 throw new IllegalStateException("newResponse() must not return null"); 157 } 158 159 // and make it the current one 160 getRequestCycle().setResponse(response); 161 162 // Invoke default execution 163 code.run(); 164 165 try 166 { 167 // Tranform the data 168 CharSequence output = transform(this, response.toString()); 169 webResponse.write(output); 170 } 171 catch (Exception ex) 172 { 173 throw new WicketRuntimeException("Error while transforming the output: " + this, ex); 174 } 175 } 176 finally 177 { 178 // Restore the original response 179 getRequestCycle().setResponse(webResponse); 180 } 181 } 182}