/* * Copyright 2008-2010 the T2 Project ant the Others. * * 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 org.t2framework.confeito.spi.impl; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Modifier; import java.util.Map; import java.util.Properties; import org.t2framework.confeito.adapter.ContainerAdapter; import org.t2framework.confeito.adapter.SimpleContainerAdapter; import org.t2framework.confeito.exception.IORuntimeException; import org.t2framework.confeito.internal.PageUtil; import org.t2framework.confeito.spi.PageRegistrationCommand; import org.t2framework.confeito.spi.PageRegistrationHandler; import org.t2framework.confeito.urltemplate.UrlTemplate; import org.t2framework.confeito.util.ArrayUtil; import org.t2framework.confeito.util.Logger; import org.t2framework.confeito.util.ResourceUtil; import org.t2framework.confeito.util.StringUtil; import org.t2framework.confeito.util.Reflections.ClassUtil; /** * <p> * Faster page registration handler. * </p> * <p> * This implementation of {@link PageRegistrationHandler} provides faster * registration process than usual directory traversal approach.However, * developer must provide page.properties which is configuration file to let T2 * framework know where and how many page classes exists.If not provide * page.properties, then T2 framework does fallback automatically to the default * {@link PageRegistrationHandler}, directory traversal approach. * </p> * <p> * To use this, developer must register this class to {@link ContainerAdapter}. * For example, with {@link SimpleContainerAdapter}, the configuration is * something like this: * </p> * <p> * <init-param><br /> *   <param-name>t2.components</param-name><br /> *   <param-value>org.t2framework.t2.spi.impl. * FastPageRegistrationHandlerImpl</param-value><br/> * </init-param> * </p> * * @author shot * @since 0.6.3 */ public class FastPageRegistrationHandlerImpl implements PageRegistrationHandler { /** * <#if locale="en"> * <p> * The class name as logging key. * </p> * <#else> * <p> * * </p> * </#if> */ protected static final String CLASS_NAME = FastPageRegistrationHandlerImpl.class .getName(); /** * <#if locale="en"> * <p> * The logger for registration succeed. * </p> * <#else> * <p> * * </p> * </#if> */ protected static Logger success = Logger.getLogger(CLASS_NAME + ".success"); /** * <#if locale="en"> * <p> * The logger for ignoring classes. * </p> * <#else> * <p> * * </p> * </#if> */ protected static Logger ignored = Logger.getLogger(CLASS_NAME + ".ignored"); /** * The logger for this class. */ protected static Logger logger = Logger.getLogger(CLASS_NAME); /** * <#if locale="en"> * <p> * Page class registration properties file. * </p> * <#else> * <p> * * </p> * </#if> */ protected static final String PROPERTIES_NAME = "page.properties"; /** * Execute registration process with page.properties. */ @Override public PageRegistrationCommand handle(String packageName, Map<Class<?>, UrlTemplate> classCache) { final Properties props = loadProperties(PROPERTIES_NAME); if (props == null) { logger.log("ITDT0056"); return PageRegistrationCommand.CONTINUE; } final String[] pageCandidates = getPageCandidates(packageName, props); if (ArrayUtil.isEmpty(pageCandidates)) { logger.log("ITDT0038"); return PageRegistrationCommand.CONTINUE; } else { return processPage(packageName, pageCandidates, classCache); } } protected PageRegistrationCommand processPage(String packageName, String[] pageCandidates, Map<Class<?>, UrlTemplate> classCache) { for (String shortClassName : pageCandidates) { final String classname = packageName + "." + shortClassName; Class<Object> c = ClassUtil.forNameNoException(classname); if (c == null) { ignored.log("ITDT0037", new Object[] { packageName, shortClassName }); continue; } else if (isAnnotationOrEnum(c)) { ignored.log("ITDT0030", new Object[] { packageName, shortClassName }); continue; } else if (isNotPublicConcreteClass(c)) { ignored.log("ITDT0031", new Object[] { packageName, shortClassName }); continue; } processPage(c, classCache); } return PageRegistrationCommand.STOP; } protected String[] getPageCandidates(String packageName, Properties props) { String s = props.getProperty(packageName); return StringUtil.split(s, ", "); } protected Properties loadProperties(String propertiesName) { final InputStream is = ResourceUtil .getResourceAsStreamNoException(PROPERTIES_NAME); if (is == null) { return null; } Properties props = new Properties(); try { props.load(is); } catch (IOException e) { throw new IORuntimeException(e); } return props; } private boolean isNotPublicConcreteClass(Class<Object> c) { final int mod = c.getModifiers(); return Modifier.isInterface(mod) || Modifier.isAbstract(mod) || Modifier.isPublic(mod) == false; } private boolean isAnnotationOrEnum(Class<Object> c) { return c.isAnnotation() || c.isEnum(); } protected void processPage(Class<?> cd, Map<Class<?>, UrlTemplate> classCache) { if (PageUtil.isPageClass(cd) == false) { return; } final UrlTemplate template = PageUtil.toUrlTemplate(cd); final String className = cd.getName(); if (template != null) { success.log("ITDT0034", new Object[] { className }); classCache.put(cd, template); } else { ignored.log("ITDT0032", new Object[] { className }); } } }