/* * Copyright (c) 2002-2012 Alibaba Group Holding Limited. * All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.alibaba.citrus.service.velocity.impl; import static com.alibaba.citrus.util.Assert.ExceptionType.*; import static com.alibaba.citrus.util.Assert.*; import static com.alibaba.citrus.util.CollectionUtil.*; import java.lang.reflect.Method; import java.util.List; import com.alibaba.citrus.service.template.TemplateException; import com.alibaba.citrus.service.velocity.FastCloneable; import org.apache.velocity.app.event.EventCartridge; import org.apache.velocity.app.event.EventHandler; import org.apache.velocity.runtime.RuntimeServices; import org.apache.velocity.util.ContextAware; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * 扩展<code>EventCartridge</code>,增加如下功能: * <ul> * <li>只在系统初始化的时候初始化一次。</li> * <li>假如event handler实现了<code>ContextAware</code>接口,则每次执行时复制一份。</li> * </ul> * * @author Michael Zhou */ public class CloneableEventCartridge extends EventCartridge { private final static Logger log = LoggerFactory.getLogger(CloneableEventCartridge.class); private final static Method cloneMethod = getCloneMethod(); private final List<EventHandler> allHandlers = createLinkedList(); private boolean initialized; private boolean needsClone = false; private static Method getCloneMethod() { Method method = null; try { method = Object.class.getDeclaredMethod("clone"); method.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException(e); } return method; } /** 在系统启动时初始化一次。 */ public void initOnce(RuntimeServices rs) throws Exception { if (!initialized) { super.initialize(rs); initialized = true; } } @Override public void initialize(RuntimeServices rs) throws Exception { assertTrue(initialized, ILLEGAL_STATE, "not initialized yet"); } @Override public boolean addEventHandler(EventHandler ev) { boolean supported = super.addEventHandler(ev); if (supported) { allHandlers.add(ev); if (ev instanceof ContextAware) { needsClone = true; if (!(ev instanceof FastCloneable)) { if (ev instanceof Cloneable) { log.warn("EventHandler which implements ContextAware and Cloneable " + "may slow down the velocity rendering process: {}", ev.getClass().getName()); } else { throw new IllegalArgumentException( "EventHandler which implements ContextAware should also implements FastCloneable or Cloneable: " + ev.getClass().getName()); } } } } return supported; } public EventCartridge getRuntimeInstance() { EventCartridge runtimeInstance = this; if (needsClone) { runtimeInstance = new EventCartridge(); for (EventHandler ev : allHandlers) { if (ev instanceof ContextAware) { if (ev instanceof FastCloneable) { ev = (EventHandler) ((FastCloneable) ev).createCopy(); } else { try { ev = (EventHandler) cloneMethod.invoke(ev); } catch (Exception e) { throw new TemplateException("Could not clone a ContextAware event handler: " + ev.getClass().getName(), e); } } } runtimeInstance.addEventHandler(ev); } } return runtimeInstance; } }