/* * Copyright (C) 2014 Civilian Framework. * * Licensed under the Civilian License (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.civilian-framework.org/license.txt * * 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.civilian.resource.scan; import java.util.ArrayList; import java.util.Collections; import org.civilian.Resource; import org.civilian.controller.ControllerSignature; import org.civilian.resource.PathParam; import org.civilian.util.StringUtil; /** * ResourceInfo holds information about a Resource. * It is created during resource scan and can be used * to create a runtime resource tree or to generate * a resources class. */ public class ResourceInfo implements Comparable<ResourceInfo> { /** * Creates a info object for the root resource. */ public ResourceInfo() { parent_ = null; segment_ = null; pathParam_ = null; path_ = "/"; } /** * Creates a info object for a child resource which * is mapped to the part. */ private ResourceInfo(ResourceInfo parent, ResourcePart part) { parent_ = parent; segment_ = part.segment; pathParam_ = part.pathParam; path_ = parent.appendPath(segment_ != null ? '/' + segment_ : pathParam_.toString()); } public ResourceInfo getParent() { return parent_; } public boolean isRoot() { return parent_ == null; } private String appendPath(String s) { return parent_ != null ? path_ + s : s; } public String getSegment() { return segment_; } public PathParam<?> getPathParam() { return pathParam_; } /** * Returns the number of child Path objects. */ public int getChildCount() { return children_ != null ? children_.size() : 0; } /** * Returns the i-th child. */ public ResourceInfo getChild(int i) { return children_.get(i); } public ResourceInfo getChild(ResourcePart part) { for (int i=0; i<getChildCount(); i++) { ResourceInfo child = getChild(i); if ((part.segment != null) ? part.segment.equals(child.segment_) : (part.pathParam == child.pathParam_)) return child; } return addChild(new ResourceInfo(this, part)); } private ResourceInfo addChild(ResourceInfo path) { if (children_ == null) children_ = new ArrayList<>(); children_.add(path); return path; } public void setPackage(ControllerPackage cp) { if (package_ != null) throw new ScanException("path '" + path_ + "' is mapped to package '" + package_ + "' and '" + cp + "'"); package_ = cp; } public ControllerPackage getPackage() { return package_; } public void setControllerInfo(String className, String methodPath) { if (controllerSignature_ != null) throw new ScanException("resource '" + path_ + "' is mapped to class '" + className + "' and '" + controllerSignature_ + "'"); controllerSignature_ = ControllerSignature.build(className, methodPath); } public String getControllerSignature() { return controllerSignature_; } /** * Returns a Java (inner) class name for this resource, * used by the generator of the Java resources class. */ public String getJavaClass() { if (isRoot()) return "Root"; else if (segment_ != null) return StringUtil.startUpperCase(segment_); else return '$' + StringUtil.startUpperCase(pathParam_.getName()); } /** * Returns a Java field name for this resource object, * used by the generator of the Java resources class. */ public String getJavaField() { if (isRoot()) return "root"; else if (segment_ != null) return StringUtil.startLowerCase(segment_); else return '$' + StringUtil.startLowerCase(pathParam_.getName()); } /** * Recursively sorts the resource children. */ public void sortChildren() { if (children_ != null) { Collections.sort(children_); for (ResourceInfo child : children_) child.sortChildren(); } } /** * Sorts the children lexicographically by their path string. * (Mostly to have a nice ordering in the generated resource class, * or in Civilian Admin). * At runtime the resources will be sorted again, * prioritizing nodes with a segment! * (see ResourceNode.compareTo) */ @Override public int compareTo(ResourceInfo other) { return path_.compareTo(other.path_); } @Override public int hashCode() { return path_.hashCode(); } @Override public boolean equals(Object other) { return (other instanceof ResourceInfo) && (((ResourceInfo)other).path_.equals(path_)); } @Override public String toString() { return path_; } /** * Creates a resource tree out of this info. */ public Resource toResource() { if (!isRoot()) throw new IllegalStateException("not root"); return new RtResource(this); } /** * Runtime class for conversion of a ResourceInfo tree into a Resource tree. */ private static class RtResource extends Resource { public RtResource(ResourceInfo resInfo) { setControllerSignature(resInfo.controllerSignature_); addChildren(resInfo); } public RtResource(Resource parent, ResourceInfo resInfo) { super(parent, resInfo.segment_, resInfo.pathParam_); setControllerSignature(resInfo.controllerSignature_); addChildren(resInfo); } private void addChildren(ResourceInfo resInfo) { int n = resInfo.getChildCount(); for (int i=0; i<n; i++) new RtResource(this, resInfo.getChild(i)); } } private final ResourceInfo parent_; private final PathParam<?> pathParam_; private final String segment_; private final String path_; private ControllerPackage package_; private String controllerSignature_; private ArrayList<ResourceInfo> children_; }