package ameba.mvc.assets; import ameba.util.IOUtils; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.glassfish.jersey.server.model.ModelProcessor; import org.glassfish.jersey.server.model.Resource; import org.glassfish.jersey.server.model.ResourceModel; import javax.ws.rs.ConstrainedTo; import javax.ws.rs.RuntimeType; import javax.ws.rs.core.Configuration; import javax.ws.rs.core.Feature; import javax.ws.rs.core.FeatureContext; import java.io.File; import java.net.MalformedURLException; import java.net.URL; import java.util.List; import java.util.Map; /** * <p>AssetsFeature class.</p> * * @author ICode * @since 13-8-17 下午2:55 * */ @ConstrainedTo(RuntimeType.SERVER) public class AssetsFeature implements Feature { /** * Constant <code>ROOT_MAPPING_PATH="/*"</code> */ public static final String ROOT_MAPPING_PATH = "/*"; private static final Map<String, String[]> assetsMap = Maps.newLinkedHashMap(); private static final String ASSETS_CONF_PREFIX = "resource.assets."; /** * <p>getAssetMap.</p> * * @param configuration a {@link javax.ws.rs.core.Configuration} object. * @return a {@link java.util.Map} object. */ public static Map<String, String[]> getAssetMap(Configuration configuration) { Map<String, String[]> assetsMap = Maps.newLinkedHashMap(); for (String key : configuration.getPropertyNames()) { if (key.startsWith(ASSETS_CONF_PREFIX) || key.equals("resource.assets")) { String routePath = key.replaceFirst("^resource\\.assets", ""); if (routePath.startsWith(".")) { routePath = routePath.substring(1); } else if (StringUtils.isBlank(routePath)) { routePath = "assets"; } if (routePath.endsWith("/")) { routePath = routePath.substring(0, routePath.lastIndexOf("/")); } String value = (String) configuration.getProperty(key); String[] uris = value.split(","); List<String> uriList = Lists.newArrayList(); for (String uri : uris) { uriList.add(uri.endsWith("/") ? uri : uri + "/"); } if (StringUtils.isNotBlank(value)) { String[] _uris = assetsMap.get(routePath); if (_uris == null) { assetsMap.put(routePath, uriList.toArray(uris)); } else { assetsMap.put(routePath, ArrayUtils.addAll(_uris, uriList.toArray(uris))); } } } } return assetsMap; } /** * <p>Getter for the field <code>assetsMap</code>.</p> * * @return a {@link java.util.Map} object. */ public static Map<String, String[]> getAssetsMap() { return Maps.newHashMap(assetsMap); } /** * <p>lookupAsset.</p> * * @param name a {@link java.lang.String} object. * @param file a {@link java.lang.String} object. * @return a {@link java.net.URL} object. */ public static URL lookupAsset(String name, String file) { URL url = null; if (name.startsWith("/")) { name = name.substring(1); } if (name.endsWith("/")) { name = name.substring(0, name.lastIndexOf("/")); } if (name.equals("")) { name = ROOT_MAPPING_PATH; } if (file.startsWith("/")) { file = file.substring(1); } String[] dirs = assetsMap.get(name); if (dirs != null) { for (String dir : dirs) { File f = FileUtils.getFile(dir, file); if (f.exists() && f.isFile()) { try { url = f.getAbsoluteFile().toURI().toURL(); } catch (MalformedURLException e) { // } } if (url == null) { url = IOUtils.getResource(dir + file); } if (url != null) { break; } } } return url; } /** {@inheritDoc} */ @Override public boolean configure(FeatureContext context) { Configuration configuration = context.getConfiguration(); assetsMap.putAll(getAssetMap(configuration)); context.register(new ModelProcessor() { @Override public ResourceModel processResourceModel(ResourceModel resourceModel, Configuration configuration) { ResourceModel.Builder resourceModelBuilder = new ResourceModel.Builder(resourceModel, false); for (String routePath : assetsMap.keySet()) { Resource.Builder resourceBuilder = Resource.builder(AssetsResource.class); if (routePath.equals(ROOT_MAPPING_PATH)) { routePath = "/"; } resourceBuilder.path(routePath); Resource resource = resourceBuilder.build(); resourceModelBuilder.addResource(resource); } return resourceModelBuilder.build(); } @Override public ResourceModel processSubResource(ResourceModel subResourceModel, Configuration configuration) { return subResourceModel; } }); return true; } }