Changeset 674
- Timestamp:
- 2008-10-07 08:54:31 (5 years ago)
- Location:
- trunk
- Files:
-
- 5 added
- 6 edited
-
modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/components/DirectoryRouter.java (modified) (6 diffs)
-
modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/components/ReloadableResource.java (added)
-
modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/groovybuild/GroovyKauriRouterBuilder.java (modified) (1 diff)
-
modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/groovybuild/factory/DirectoryRouterFactory.java (modified) (3 diffs)
-
modules/kauri-routing/kauri-routing-impl/src/test/java/org/kauriproject/routing/test/Routing2Test.java (modified) (3 diffs)
-
modules/kauri-routing/kauri-routing-impl/src/test/modulesrc/org/kauriproject/routing/test/testmodules/routing2/KAURI-INF/router.groovy (modified) (1 diff)
-
modules/kauri-routing/kauri-routing-impl/src/test/modulesrc/org/kauriproject/routing/test/testmodules/routing2/KAURI-INF/site/pages/.startswithdot.html (added)
-
modules/kauri-routing/kauri-routing-impl/src/test/modulesrc/org/kauriproject/routing/test/testmodules/routing2/KAURI-INF/site/pages/differentextension.html.xml (added)
-
modules/kauri-routing/kauri-routing-impl/src/test/modulesrc/org/kauriproject/routing/test/testmodules/routing2/KAURI-INF/site/pages/ignorethis (added)
-
modules/kauri-routing/kauri-routing-impl/src/test/modulesrc/org/kauriproject/routing/test/testmodules/routing2/KAURI-INF/site/pages/noextension..html (added)
-
universe/kauri-template/src/main/java/org/kauriproject/template/DefaultTemplateBuilder.java (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
-
trunk/modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/components/DirectoryRouter.java
r672 r674 4 4 import org.restlet.Router; 5 5 import org.restlet.Context; 6 import org.restlet.util.Template; 6 7 import org.restlet.resource.Representation; 7 import org.restlet.data.Request; 8 import org.restlet.data.Response; 9 import org.restlet.data.MediaType; 8 import org.restlet.data.*; 10 9 import org.kauriproject.runtime.rapi.KauriModule; 11 10 import org.kauriproject.runtime.rapi.ModuleSource; 12 11 import org.kauriproject.runtime.rapi.ModuleSource.Resource; 13 12 import org.kauriproject.template.service.TemplateService; 13 import org.kauriproject.routing.impl.routing.DisposableRoutingComponent; 14 14 import org.apache.commons.logging.LogFactory; 15 15 import org.apache.commons.logging.Log; … … 18 18 import java.util.regex.Pattern; 19 19 import java.util.regex.Matcher; 20 import java.io.File; 20 21 21 22 /** … … 24 25 * are supposed to be executable templates. 25 26 */ 26 public class DirectoryRouter extends Restlet { 27 private String path; 28 private Router router; 27 public class DirectoryRouter extends Restlet implements DisposableRoutingComponent { 28 private String root; 29 29 private ModuleSource moduleSource; 30 30 private TemplateService templateService; 31 31 private Context restletContext; 32 private Log log = LogFactory.getLog(getClass()); 33 34 private static Pattern DOUBLE_EXT = Pattern.compile("^(.*)\\.([^.]*)\\.([^.]+)$"); 35 36 public DirectoryRouter(String path, Context restletContext, KauriModule module, TemplateService templateService) { 37 this.path = path.replaceFirst("^/+", ""); 32 private ReloadableResource reloadableResource; 33 private List<Pattern> ignoreFilePatterns = new ArrayList<Pattern>(); 34 private final Log log = LogFactory.getLog(getClass()); 35 36 /** 37 * Explanation of this pattern: the purpose is to match file paths where the file 38 * name has a "double extension" (e.g. "/somedir/file.html.xml). The second-last 39 * extension is allowed to be empty (e.g. "/somedir/file..xml). If the file name 40 * starts with a dot, then it doesn't count as a double extension (e.g. "/somedir/.file.html"). 41 */ 42 private static Pattern DOUBLE_EXT = Pattern.compile("^(.*(?:[^/]+))\\.([^./]*)\\.([^./]+)$"); 43 44 public DirectoryRouter(String root, Context restletContext, KauriModule module, TemplateService templateService, List<String> ignoreFilePatterns) { 45 this.root = root.replaceFirst("^/+", ""); 38 46 this.restletContext = restletContext; 39 47 this.moduleSource = module.getSource(); 40 48 this.templateService = templateService; 49 this.reloadableResource = new ReloadableResource(moduleSource, root, new DirectoryRouterBuilder(), new FAMListener(), "pages-restlet"); 50 51 for (String pattern : ignoreFilePatterns) { 52 pattern = pattern.trim(); 53 if (pattern.length() > 0) 54 this.ignoreFilePatterns.add(compileWildcardPattern(pattern)); 55 } 56 } 57 58 public void dispose() { 59 reloadableResource.disposeReloading(); 41 60 } 42 61 43 62 @Override 44 63 public void handle(Request request, Response response) { 45 build(); 46 router.handle(request, response); 47 } 48 49 private void build() { 64 ((Restlet)reloadableResource.build()).handle(request, response); 65 } 66 67 public Object build() { 50 68 List<Page> pages = new ArrayList<Page>(); 51 scan( path, "", pages);69 scan(root, "", pages); 52 70 53 71 // The "best" matching algorithm of Restlet's Router cannot meaningfully … … 66 84 67 85 Router router = new Router(); 86 router.setDefaultMatchingMode(Template.MODE_EQUALS); 87 router.setDefaultMatchQuery(false); 68 88 for (Page page : pages) { 69 89 if (log.isDebugEnabled()) { … … 72 92 router.attach(page.uriPattern, new TemplateRestlet(templateService, restletContext, page.templatePath)); 73 93 } 74 this.router =router;75 } 76 77 private void scan(String parent, String mountPath, Collection<Page> pages) {78 Resource res = moduleSource.getResource( parent);94 return router; 95 } 96 97 private void scan(String filePath, String mountPath, Collection<Page> pages) { 98 Resource res = moduleSource.getResource(filePath); 79 99 80 100 Collection<String> children = res.getChildren(); 81 101 for (String child : children) { 82 String childPath = parent + "/" + child; 83 Resource childRes = moduleSource.getResource(childPath); 102 if (ignore(child)) 103 continue; 104 105 String childFilePath = filePath + "/" + child; 106 String childMountPath = mountPath + "/" + child; 107 Resource childRes = moduleSource.getResource(childFilePath); 84 108 if (childRes.isDirectory()) { 85 scan(child Path, mountPath + "/" + child, pages);109 scan(childFilePath, childMountPath, pages); 86 110 } else { 87 pages.add(createPage(mountPath + "/" + child)); 88 } 89 } 90 } 91 92 private static class TemplateRestlet extends Restlet { 93 private TemplateService templateService; 94 private Context restletContext; 95 private String templatePath; 96 97 private TemplateRestlet(TemplateService templateService, Context restletContext, String templatePath) { 98 this.templateService = templateService; 99 this.restletContext = restletContext; 100 this.templatePath = templatePath; 101 } 102 103 @Override 104 public void handle(Request request, Response response) { 105 // TODO only allow GET method ? 106 Map<String, Object> parameters = new HashMap<String, Object>(); 107 parameters.put("request", request); 108 Representation representation = templateService.getTemplateRepresentation(MediaType.TEXT_HTML, restletContext, request, templatePath, parameters); 109 response.setEntity(representation); 110 } 111 pages.add(createPage(childMountPath)); 112 } 113 } 114 } 115 116 /** 117 * Compiles a string containing '*' wildcards to a regular expression. 118 */ 119 private Pattern compileWildcardPattern(String pattern) { 120 StringBuilder result = new StringBuilder(); 121 StringBuilder buffer = new StringBuilder(); 122 123 char c; 124 for (int i = 0; i < pattern.length(); i++) { 125 c = pattern.charAt(i); 126 if (c == '*') { 127 if (buffer.length() > 0) { 128 result.append(Pattern.quote(buffer.toString())); 129 buffer.setLength(0); 130 } 131 result.append(".*"); 132 } else { 133 buffer.append(c); 134 } 135 } 136 137 if (buffer.length() > 0) { 138 result.append(Pattern.quote(buffer.toString())); 139 } 140 141 return Pattern.compile(result.toString()); 142 } 143 144 private boolean ignore(String name) { 145 for (Pattern pattern : ignoreFilePatterns) { 146 if (pattern.matcher(name).matches()) 147 return true; 148 } 149 return false; 111 150 } 112 151 113 152 private Page createPage(String filePath) { 114 String templatePath = "kms:/" + this. path+ filePath;153 String templatePath = "kms:/" + this.root + filePath; 115 154 Matcher matcher = DOUBLE_EXT.matcher(filePath); 116 155 if (matcher.matches()) { 156 // Double extension feature: the purpose is to allow a file to 157 // have a different extension on the file system and in the public 158 // URI path. It also allows to have no extension in the URI path, 159 // while having an extension on the file system. 160 // For example: 161 // File path URI path 162 // /somedir/file.html.xml /somedir/file.html 163 // /somedir/file..xml /somedir/file 164 // The double extension rule doesn't count if the file starts with 165 // a dot. 117 166 String base = matcher.group(1); 118 167 String publicExt = matcher.group(2); … … 135 184 } 136 185 } 186 187 private static class TemplateRestlet extends Restlet { 188 private TemplateService templateService; 189 private Context restletContext; 190 private String templatePath; 191 192 private TemplateRestlet(TemplateService templateService, Context restletContext, String templatePath) { 193 this.templateService = templateService; 194 this.restletContext = restletContext; 195 this.templatePath = templatePath; 196 } 197 198 @Override 199 public void handle(Request request, Response response) { 200 if (request.getMethod().equals(Method.GET)) { 201 Map<String, Object> parameters = new HashMap<String, Object>(); 202 parameters.put("request", request); 203 Representation representation = templateService.getTemplateRepresentation(MediaType.TEXT_HTML, restletContext, request, templatePath, parameters); 204 response.setEntity(representation); 205 } else { 206 response.setStatus(Status.CLIENT_ERROR_METHOD_NOT_ALLOWED); 207 } 208 } 209 } 210 211 private class DirectoryRouterBuilder implements ReloadableResource.ResourceBuilder { 212 public Object build() { 213 return DirectoryRouter.this.build(); 214 } 215 } 216 217 private class FAMListener implements ReloadableResource.FAMListener { 218 public boolean onFileCreate(File file) { 219 return true; 220 } 221 222 public boolean onFileChange(File file) { 223 return true; 224 } 225 226 public boolean onFileDelete(File file) { 227 return true; 228 } 229 230 public boolean onDirectoryCreate(File file) { 231 return true; 232 } 233 234 public boolean onDirectoryChange(File file) { 235 return true; 236 } 237 238 public boolean onDirectoryDelete(File file) { 239 return true; 240 } 241 } 137 242 } -
trunk/modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/groovybuild/GroovyKauriRouterBuilder.java
r671 r674 45 45 restletBuilder.registerFactory(JaxRsGroovyScriptsFactory.METHOD_NAME, new JaxRsGroovyScriptsFactory()); 46 46 restletBuilder.registerFactory(ReadFactory.METHOD_NAME, new ReadFactory(context)); 47 restletBuilder.registerFactory(DirectoryRouterFactory.METHOD_NAME, new DirectoryRouterFactory(context, module, routingConfig.getTemplateService() ));47 restletBuilder.registerFactory(DirectoryRouterFactory.METHOD_NAME, new DirectoryRouterFactory(context, module, routingConfig.getTemplateService(), buildContext)); 48 48 restletBuilder.registerFactory(TemplateFactory.METHOD_NAME, new TemplateFactory(context, routingConfig.getTemplateService())); 49 49 restletBuilder.registerFactory(ModeFactory.METHOD_NAME, new ModeFactory(module)); -
trunk/modules/kauri-routing/kauri-routing-impl/src/main/java/org/kauriproject/routing/impl/groovybuild/factory/DirectoryRouterFactory.java
r651 r674 4 4 import org.kauriproject.routing.impl.components.DirectoryRouter; 5 5 import org.kauriproject.routing.impl.RoutingConfigurationException; 6 import org.kauriproject.routing.impl.routing.RouterBuildContext; 6 7 import org.kauriproject.runtime.rapi.KauriModule; 7 8 import org.kauriproject.template.service.TemplateService; … … 9 10 10 11 import java.util.Map; 12 import java.util.List; 13 import java.util.Arrays; 14 import java.util.ArrayList; 11 15 12 16 public class DirectoryRouterFactory extends RestletFactory { 13 17 public static final String METHOD_NAME = "directoryRouter"; 14 18 private static final String ROOT = "root"; 19 private static final String IGNORE = "ignore"; 15 20 16 21 private Context context; 17 22 private KauriModule kauriModule; 18 23 private TemplateService templateService; 24 private RouterBuildContext buildContext; 25 private static List<String> BUILD_IN_IGNORES; 26 static { 27 BUILD_IN_IGNORES = new ArrayList<String>(); 28 BUILD_IN_IGNORES.add(".svn"); 29 BUILD_IN_IGNORES.add("CVS"); 30 BUILD_IN_IGNORES.add(".DS_Store"); 31 BUILD_IN_IGNORES.add("SCCS"); 32 BUILD_IN_IGNORES.add("RCS"); 33 BUILD_IN_IGNORES.add("rcs"); 34 BUILD_IN_IGNORES.add(".sbas"); 35 BUILD_IN_IGNORES.add(".IJI.*"); 36 BUILD_IN_IGNORES.add("vssver.scc"); 37 BUILD_IN_IGNORES.add("vssver2.scc"); 38 } 19 39 20 public DirectoryRouterFactory(Context context, KauriModule kauriModule, TemplateService templateService) { 40 public DirectoryRouterFactory(Context context, KauriModule kauriModule, TemplateService templateService, 41 RouterBuildContext buildContext) { 21 42 super(); 22 43 this.context = context; 23 44 this.kauriModule = kauriModule; 24 45 this.templateService = templateService; 25 addFilter(ROOT); 46 this.buildContext = buildContext; 47 addFilter(ROOT).addFilter(IGNORE); 26 48 } 27 49 … … 31 53 throw new RoutingConfigurationException(METHOD_NAME + " is used in the routing configuration, but no template service implementation is provided."); 32 54 String rootPath = (String)builder.getContext().get(ROOT); 33 DirectoryRouter dirRouter = new DirectoryRouter(rootPath, context, kauriModule, templateService); 55 String ignoreSpec = (String)builder.getContext().get(IGNORE); 56 List<String> ignores = ignoreSpec != null ? Arrays.asList(ignoreSpec.split(" ")) : BUILD_IN_IGNORES; 57 DirectoryRouter dirRouter = new DirectoryRouter(rootPath, context, kauriModule, templateService, ignores); 58 buildContext.addDisposable(dirRouter); 34 59 return dirRouter; 35 60 } -
trunk/modules/kauri-routing/kauri-routing-impl/src/test/java/org/kauriproject/routing/test/Routing2Test.java
r671 r674 10 10 import java.util.Collections; 11 11 12 /** 13 * Test case for directory router, sequence router, and runtime mode switch. 14 */ 12 15 public class Routing2Test extends AbstractRuntimeTest { 13 16 private KauriRuntime runtime; … … 55 58 assertEquals(200, response.getStatus().getCode()); 56 59 assertTrue(response.getEntity().getText().indexOf("Always here") > -1); 60 61 response = get("/ignorethis"); 62 assertEquals(404, response.getStatus().getCode()); 63 64 response = get("/.startswithdot.html"); 65 assertEquals(200, response.getStatus().getCode()); 66 67 response = get("/differentextension.html"); 68 assertEquals(200, response.getStatus().getCode()); 69 70 response = get("/differentextension.html.xml"); 71 assertEquals(404, response.getStatus().getCode()); 72 73 response = get("/noextension"); 74 assertEquals(200, response.getStatus().getCode()); 75 76 response = get("/noextension."); 77 assertEquals(404, response.getStatus().getCode()); 78 79 response = get("/noextension..html"); 80 assertEquals(404, response.getStatus().getCode()); 57 81 } finally { 58 82 runtime.stop(); … … 73 97 assertEquals(200, response.getStatus().getCode()); 74 98 assertTrue(response.getEntity().getText().indexOf("Always here") > -1); 99 100 // for production, we didn't set the ignore filter, so the file should be accessible 101 response = get("/ignorethis"); 102 assertEquals(200, response.getStatus().getCode()); 75 103 } finally { 76 104 runtime.stop(); -
trunk/modules/kauri-routing/kauri-routing-impl/src/test/modulesrc/org/kauriproject/routing/test/testmodules/routing2/KAURI-INF/router.groovy
r671 r674 1 1 builder.router { 2 2 mode(uri: "", continueIfNotFound: true, when: "prototype") { 3 directoryRouter(root: "/site/pages" )3 directoryRouter(root: "/site/pages", ignore: ".svn CVS ignorethis") 4 4 } 5 5 -
trunk/universe/kauri-template/src/main/java/org/kauriproject/template/DefaultTemplateBuilder.java
r656 r674 112 112 xmlReader.parse(new InputSource(in)); 113 113 complete = CompiledTemplate.COMPLETE; 114 } catch (SAXException saxex) { 115 log.error(saxex); 116 } catch (IOException ioex) { 117 log.error(ioex); 114 } catch (Exception ex) { 115 // TODO 116 throw new RuntimeException("Error parsing template file " + source.getReference(), ex); 118 117 } finally { 119 118 try {
Note: See TracChangeset
for help on using the changeset viewer.