package org.beanfuse.struts2.route.impl;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.lang.StringUtils;
import org.beanfuse.struts2.route.ActionNameBuilder;
import org.beanfuse.struts2.route.Convention;
import org.beanfuse.struts2.route.Profile;
import org.beanfuse.struts2.route.ProfileService;
import org.beanfuse.struts2.route.ViewMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ProfileServiceImpl implements ProfileService {
private final static Logger logger = LoggerFactory.getLogger(ProfileServiceImpl.class);
private List<Profile> profiles = new ArrayList<Profile>();
private Profile defaultProfile = new Profile();
// 匹配缓存[String,Profile]
private Map<String, Profile> cache = new HashMap();
public ProfileServiceImpl() {
super();
defaultProfile.setViewExtension("ftl");
defaultProfile.setDefaultMethod("index");
defaultProfile.setUriStyle(ActionNameBuilder.SEO);
defaultProfile.setUriExtension("action");
defaultProfile.setActionSuffix("Action");
defaultProfile.setViewPath("/pages/");
defaultProfile.setPathStyle(ViewMapper.SIMPLE);
loadProfiles();
}
public Profile getProfile(String className) {
Profile matched = cache.get(className);
if (null != matched) {
return matched;
}
int index = -1;
for (Profile profile : profiles) {
int newIndex = profile.matchedIndex(className);
if (newIndex > index) {
matched = profile;
index = newIndex;
}
}
if (matched == null) {
matched = defaultProfile;
}
synchronized (cache) {
cache.put(className, matched);
}
logger.debug("{} match profile:{}", className, matched.getPattern());
return matched;
}
public Profile getProfile(Class clazz) {
return getProfile(clazz.getName());
}
private Properties getProperties(URL url) {
logger.debug("loading {}", url);
InputStream in = null;
try {
in = url.openStream();
if (in != null) {
Properties p = new Properties();
p.load(in);
return p;
}
} catch (IOException e) {
logger.error("Error while loading " + url, e);
} finally {
if (in != null) {
try {
in.close();
} catch (IOException io) {
logger.warn("Unable to close input stream", io);
}
}
}
return null;
}
/**
* 初始化配置
*/
public void loadProfiles() {
try {
URL convention_default = ProfileServiceImpl.class.getClassLoader().getResource(
"convention-default.properties");
Properties props = getProperties(convention_default);
defaultProfile = populatProfile(props, "default");
if (null == defaultProfile) {
throw new RuntimeException("cannot find default profile !");
}
populateProfiles(props);
Enumeration<URL> em = ProfileServiceImpl.class.getClassLoader().getResources(
"META-INF/convention-route.properties");
while (em.hasMoreElements()) {
props = getProperties(em.nextElement());
populateProfiles(props);
}
// 不要排序,让用户决定那个先选择
// Collections.sort(profiles);
} catch (IOException e) {
throw new RuntimeException(e.getMessage());
}
}
private void populateProfiles(Properties props) {
int profileIndex = 0;
while (true) {
Profile profile = populatProfile(props, "profile" + profileIndex);
if (null == profile) {
break;
} else {
profiles.add(profile);
}
profileIndex++;
}
}
private Profile populatProfile(Properties props, String name) {
Profile profile = new Profile();
profile.setName(name);
String packageName = props.getProperty(profile.getName() + ".packageName");
if (StringUtils.isEmpty(packageName))
return null;
profile.setPackageName(packageName);
// 保证控制器前缀以点结束,默认和包路径一致
String pattern = props.getProperty(profile.getName() + ".pattern", packageName + ".");
if (!pattern.endsWith(".")) {
pattern += ".";
}
profile.setPattern(pattern);
profile.setActionSuffix(props.getProperty(profile.getName() + ".ctlPostfix", defaultProfile
.getActionSuffix()));
// 保证页面路径以/结束
profile.setViewPath(props.getProperty(profile.getName() + ".viewPath", defaultProfile
.getViewPath()));
if (!profile.getViewPath().endsWith(Convention.separator + "")) {
profile.setViewPath(profile.getViewPath() + Convention.separator);
}
populateAttr(profile, "viewExtension", props);
populateAttr(profile, "defaultMethod", props);
populateAttr(profile, "pathStyle", props);
populateAttr(profile, "uriStyle", props);
populateAttr(profile, "uriExtension", props);
return profile;
}
private void populateAttr(Profile profile, String attr, Properties props) {
Object value = props.getProperty(profile.getName() + "." + attr);
try {
if (null == value) {
value = PropertyUtils.getProperty(defaultProfile, attr);
}
PropertyUtils.setProperty(profile, attr, value);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public List<Profile> getProfiles() {
return profiles;
}
public void setProfiles(List<Profile> profiles) {
this.profiles = profiles;
}
public Profile getDefaultProfile() {
return defaultProfile;
}
public void setDefaultProfile(Profile defaultProfile) {
this.defaultProfile = defaultProfile;
}
}