package railo.runtime.rest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import railo.commons.io.FileUtil;
import railo.commons.io.res.Resource;
import railo.commons.io.res.filter.AndResourceFilter;
import railo.commons.io.res.filter.ExtensionResourceFilter;
import railo.commons.io.res.filter.ResourceFilter;
import railo.commons.lang.mimetype.MimeType;
import railo.runtime.PageContext;
import railo.runtime.PageSource;
import railo.runtime.component.ComponentLoader;
import railo.runtime.config.Config;
import railo.runtime.config.ConfigWebImpl;
import railo.runtime.config.ConfigWebUtil;
import railo.runtime.config.Constants;
import railo.runtime.exp.PageException;
import railo.runtime.op.Caster;
import railo.runtime.type.Struct;
import railo.runtime.type.StructImpl;
import railo.runtime.type.cfc.ComponentAccess;
import railo.runtime.type.util.ArrayUtil;
import railo.runtime.type.util.KeyConstants;
public class Mapping {
private static final ResourceFilter FILTER = new AndResourceFilter(new ResourceFilter[]{
new ExtensionResourceFilter(Constants.CFC_EXTENSION),
new ResourceFilter() {
public boolean accept(Resource res) {
return !Constants.APP_CFC.equalsIgnoreCase(res.getName());
}
}
});
private String virtual;
private Resource physical;
private String strPhysical;
private boolean hidden;
private boolean readonly;
private boolean _default;
private List<Source> baseSources;
private Map<Resource,List<Source>> customSources=new HashMap<Resource, List<Source>>();
public Mapping(Config config, String virtual, String physical, boolean hidden, boolean readonly, boolean _default) {
if(!virtual.startsWith("/"))this.virtual="/"+virtual;
if(virtual.endsWith("/"))this.virtual=virtual.substring(0,virtual.length()-1);
else this.virtual=virtual;
this.strPhysical=physical;
this.hidden=hidden;
this.readonly=readonly;
this._default=_default;
if(!(config instanceof ConfigWebImpl)) return;
ConfigWebImpl cw=(ConfigWebImpl) config;
this.physical=ConfigWebUtil.getExistingResource(cw.getServletContext(),physical,null,cw.getConfigDir(),FileUtil.TYPE_DIR,cw);
}
private List<Source> init(PageContext pc, boolean reset) throws PageException {
if(reset)release();
Resource[] locations = pc.getApplicationContext().getRestCFCLocations();
// base source
if(ArrayUtil.isEmpty(locations)) {
if(baseSources==null && this.physical!=null && this.physical.isDirectory()) {
baseSources=_init(pc,this, this.physical);
}
return baseSources;
}
// custom sources
List<Source> rtn = new ArrayList<Source>();
List<Source> list;
for(int i=0;i<locations.length;i++){
list = customSources.get(locations[i]);
if(list==null && locations[i].isDirectory()) {
list=_init(pc,this, locations[i]);
customSources.put(locations[i], list);
}
copy(list,rtn);
}
return rtn;
}
private void copy(List<Source> src, List<Source> trg) {
if(src==null) return;
Iterator<Source> it = src.iterator();
while(it.hasNext()){
trg.add(it.next());
}
}
private static ArrayList<Source> _init(PageContext pc, Mapping mapping, Resource dir) throws PageException{
Resource[] children = dir.listResources(FILTER);
RestSettings settings = pc.getApplicationContext().getRestSettings();
ArrayList<Source> sources = new ArrayList<Source>();
PageSource ps;
ComponentAccess cfc;
Struct meta;
String path;
for(int i=0;i<children.length;i++){
try{
ps = pc.toPageSource(children[i],null);
cfc = ComponentLoader.loadComponent(pc, null, ps, children[i].getName(), true,true);
meta = cfc.getMetaData(pc);
if(Caster.toBooleanValue(meta.get(KeyConstants._rest,null),false)){
path = Caster.toString(meta.get(KeyConstants._restPath,null),null);
sources.add(new Source(mapping, cfc.getPageSource(), path));
}
}
catch(Throwable t){
if(!settings.getSkipCFCWithError()) throw Caster.toPageException(t);
}
}
return sources;
}
public railo.runtime.rest.Mapping duplicate(Config config,Boolean readOnly) {
return new Mapping(config, virtual, strPhysical, hidden, readOnly==null?this.readonly:readOnly.booleanValue(),_default);
}
/**
* @return the physical
*/
public Resource getPhysical() {
return physical;
}
/**
* @return the virtual
*/
public String getVirtual() {
return virtual;
}
public String getVirtualWithSlash() {
return virtual+"/";
}
/**
* @return the strPhysical
*/
public String getStrPhysical() {
return strPhysical;
}
/**
* @return the hidden
*/
public boolean isHidden() {
return hidden;
}
/**
* @return the readonly
*/
public boolean isReadonly() {
return readonly;
}
public boolean isDefault() {
return _default;
}
public Result getResult(PageContext pc,String path,Struct matrix,int format,boolean hasFormatExtension, List<MimeType> accept, MimeType contentType,Result defaultValue) throws PageException {
List<Source> sources = init(pc,false);
Iterator<Source> it = sources.iterator();
Source src;
String[] arrPath,subPath;
int index;
while(it.hasNext()) {
src = it.next();
Struct variables=new StructImpl();
arrPath = RestUtil.splitPath(path);
index=RestUtil.matchPath(variables,src.getPath(),arrPath);
if(index!=-1){
subPath=new String[(arrPath.length-1)-index];
System.arraycopy(arrPath, index+1, subPath, 0, subPath.length);
return new Result(src,variables,subPath,matrix,format,hasFormatExtension,accept,contentType);
}
}
return defaultValue;
}
public void setDefault(boolean _default) {
this._default=_default;
}
public void reset(PageContext pc) throws PageException {
init(pc, true);
}
public synchronized void release() {
if(baseSources!=null) {
baseSources.clear();
baseSources = null;
}
customSources.clear();
}
}