/*
* @(#)PackageBasedUrlPathBuilder.java 2013-1-31 下午23:33:33
*
* Copyright (c) 2011-2013 Makersoft.org all rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
*
*/
package org.makersoft.web.mvc.builder;
import java.lang.reflect.Modifier;
import org.apache.commons.lang3.StringUtils;
import org.makersoft.log.Log;
import org.makersoft.log.LoggerFactory;
/**
* Class description goes here.
*/
public class PackageBasedUrlPathBuilder {
private static final Log LOG = LoggerFactory.getLogger(PackageBasedUrlPathBuilder.class);
/**
* "web", "controller", "action", "controllers"
*/
private final String[] packageLocators;
/**
* "org.makersoft.web.mvc.controllers"
*/
private final String[] controllerPackages;
/**
* root path
*/
private final String root;
private final ControllerNameBuilder builder;
/**
*
* @param packageLocators
* @param controllerPackages
* @param controllerSuffix
* @param root
*/
public PackageBasedUrlPathBuilder(String[] packageLocators, String[] controllerPackages,
String controllerSuffix, String root) {
this.packageLocators = packageLocators;
this.controllerPackages = controllerPackages;
this.root = StringUtils.isBlank(root) ? "application#index" : root;
this.builder = new SEOControllerNameBuilder(controllerSuffix);
}
/**
* 根据Controller类,截取URL
*
* @param clazz
* Controller类
* @return URL Path
*/
public String[] buildUrlPath(Class<?> controllerClass, String methodName, String... values) {
// Skip classes that can't be instantiated
if (cannotInstantiate(controllerClass)) {
if (LOG.isTraceEnabled())
LOG.trace("Class [#0] did not pass the instantiation test and will be ignored",
controllerClass.getName());
}
// Determine the action package
String controllerPackage = controllerClass.getPackage().getName();
if (LOG.isDebugEnabled()) {
LOG.debug("Processing class [#0] in package [#1]", controllerClass.getName(),
controllerPackage);
}
// Determine the default namespace and action name
String namespace = determineControllerNamespace(controllerClass);
String defaultControllerName = determineControllerName(controllerClass);
// reversion
String[] urlPaths = null;
// fixed root path
if (root.equals(defaultControllerName + "#" + methodName)) {
urlPaths = new String[] { "/" };
} else if (values.length != 0) {
urlPaths = new String[values.length];
for (int i = 0; i < values.length; i++) {
String value = values[i];
urlPaths[i] = namespace + "/" + defaultControllerName + value;
}
} else {
urlPaths = new String[] { namespace + "/" + defaultControllerName };
}
return urlPaths;
}
/**
* Determines the namespace(s) for the action based on the action class. If there is a {
* Namespace} annotation on the class (including parent classes) or on the package that the
* class is in, than it is used. Otherwise, the Java package name that the class is in is used
* in conjunction with either the <b>struts.convention.action.packages</b> or
* <b>struts.convention.package.locators</b> configuration values. These are used to determine
* which part of the Java package name should be converted into the namespace for the XWork
* PackageConfig.
*
* @param actionClass
* The action class.
* @return The namespace or an empty string.
*/
private String determineControllerNamespace(Class<?> controllerClass) {
String urlPath;
String pkg = controllerClass.getPackage().getName();
String pkgPart = null;
if (controllerPackages != null) {
for (String actionPackage : controllerPackages) {
if (pkg.startsWith(actionPackage)) {
pkgPart = controllerClass.getName().substring(actionPackage.length() + 1);
}
}
}
if (pkgPart == null && packageLocators != null) {
for (String packageLocator : packageLocators) {
int index = pkg.lastIndexOf(packageLocator);
// This ensures that the match is at the end, beginning or has a dot on each side of it
if (index >= 0
&& (index + packageLocator.length() == pkg.length() || index == 0 || (pkg
.charAt(index - 1) == '.' && pkg.charAt(index
+ packageLocator.length()) == '.'))) {
pkgPart = controllerClass.getName().substring(
index + packageLocator.length() + 1);
}
}
}
if (pkgPart != null) {
final int indexOfDot = pkgPart.lastIndexOf('.');
if (indexOfDot >= 0) {
// String convertedNamespace = this.build(pkgPart.substring(0, indexOfDot));
String convertedNamespace = pkgPart.substring(0, indexOfDot);
urlPath = "/" + convertedNamespace.replace('.', '/');
return urlPath;
}
}
return "";
}
/**
* Converts the class name into an action name using the ActionNameBuilder.
*
* @param actionClass
* The action class.
* @return The action name.
*/
protected String determineControllerName(Class<?> controllerClass) {
String controllerName = builder.build(controllerClass.getSimpleName());
if (LOG.isTraceEnabled()) {
LOG.trace("Got actionName for class [#0] of [#1]", controllerClass.toString(),
controllerName);
}
return controllerName;
}
public static String urlPathConvert(Class<?> clazz, String[] packageLocators, String... values) {
return null;
}
/**
* Interfaces, enums, annotations, and abstract classes cannot be instantiated.
*
* @param controllerClass
* class to check
* @return returns true if the class cannot be instantiated or should be ignored
*/
protected boolean cannotInstantiate(Class<?> controllerClass) {
return controllerClass.isAnnotation() || controllerClass.isInterface()
|| controllerClass.isEnum()
|| (controllerClass.getModifiers() & Modifier.ABSTRACT) != 0
|| controllerClass.isAnonymousClass();
}
}