001/* 002 * (C) Copyright 2006-2008 Nuxeo SA (http://nuxeo.com/) and others. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 * 016 * Contributors: 017 * bstefanescu 018 * 019 * $Id$ 020 */ 021 022package org.nuxeo.ecm.webengine.model.impl; 023 024import java.io.BufferedWriter; 025import java.io.File; 026import java.io.FileWriter; 027import java.io.IOException; 028import java.io.Writer; 029 030import org.apache.commons.logging.Log; 031import org.apache.commons.logging.LogFactory; 032import org.nuxeo.common.utils.FileUtils; 033import org.nuxeo.ecm.webengine.WebEngine; 034import org.nuxeo.ecm.webengine.WebException; 035import org.nuxeo.ecm.webengine.loader.ClassProxy; 036import org.nuxeo.ecm.webengine.loader.WebLoader; 037import org.nuxeo.ecm.webengine.model.WebAdapter; 038import org.nuxeo.ecm.webengine.model.WebObject; 039 040/** 041 * Load web types extracted from Groovy source files. Types are cached in META-INF/groovy-web-types. When types are 042 * reloaded this file will be removed. 043 * 044 * @author <a href="mailto:bs@nuxeo.com">Bogdan Stefanescu</a> 045 */ 046public class GroovyTypeLoader { 047 048 public static final Log log = LogFactory.getLog(GroovyTypeLoader.class); 049 050 public static final String CRLF = System.getProperty("line.separator"); 051 052 public static final String WEB_TYPES_FILE = "META-INF/groovy-web-types"; 053 054 protected final WebLoader loader; 055 056 protected final TypeRegistry typeReg; 057 058 protected final File root; 059 060 public GroovyTypeLoader(WebEngine engine, TypeRegistry typeReg, File root) { 061 this.typeReg = typeReg; 062 this.root = root; 063 loader = engine.getWebLoader(); 064 } 065 066 public synchronized void flushCache() { 067 log.info("Flush directory type provider cache"); 068 File cache = new File(root, WEB_TYPES_FILE); 069 cache.delete(); 070 } 071 072 public synchronized void load() { 073 try { 074 File cache = new File(root, WEB_TYPES_FILE); 075 if (cache.isFile()) { 076 for (String line : FileUtils.readLines(cache)) { 077 if (line.equals("")) { 078 continue; 079 } 080 TypeDescriptor td = loadType(line); 081 if (td != null) { 082 typeReg.registerTypeDescriptor(td); 083 } 084 } 085 } else { 086 cache.getParentFile().mkdirs(); 087 boolean completedAbruptly = true; 088 try (Writer w = new BufferedWriter(new FileWriter(cache))) { 089 scan(root, null, w); 090 completedAbruptly = false; 091 } finally { 092 if (completedAbruptly) { 093 cache.delete(); 094 } 095 } 096 } 097 } catch (IOException | ClassNotFoundException e) { 098 throw WebException.wrap(e); 099 } 100 } 101 102 protected void scan(File root, String path, Writer cache) { 103 for (File file : root.listFiles()) { 104 String name = file.getName(); 105 if (file.isDirectory() && !"skin".equals(name) && !"samples".equals(name)) { 106 scan(file, path == null ? name : new StringBuilder().append(path).append('.').append(name).toString(), 107 cache); 108 } else if (name.endsWith(".groovy") && Character.isUpperCase(name.charAt(0))) { 109 String className = null; 110 if (path == null) { 111 className = name.substring(0, name.length() - 7); 112 } else { 113 StringBuilder buf = new StringBuilder().append(path).append('.').append(name); 114 buf.setLength(buf.length() - 7); 115 className = buf.toString(); 116 } 117 try { 118 TypeDescriptor td = loadTypeAndRecord(cache, className); 119 if (td != null) { 120 typeReg.registerTypeDescriptor(td); 121 } 122 } catch (IOException | ClassNotFoundException e) { 123 throw WebException.wrap(e); 124 } 125 } 126 } 127 } 128 129 /** 130 * Loads a type and cache it. 131 * 132 * @param cache 133 * @param className 134 * @throws ClassNotFoundException 135 * @throws IOException 136 */ 137 protected TypeDescriptor loadTypeAndRecord(Writer cache, String className) throws ClassNotFoundException, 138 IOException { 139 TypeDescriptor td = loadType(className); 140 if (td != null) { 141 cache.write(className); 142 cache.write(CRLF); 143 } 144 return td; 145 } 146 147 /** 148 * Gets a type descriptor given an absolute className. 149 * <p> 150 * If this class doesn't define a type or type adapter, return null. 151 */ 152 protected TypeDescriptor loadType(String className) throws ClassNotFoundException { 153 ClassProxy clazz = loader.getGroovyClassProxy(className); 154 WebObject type = clazz.get().getAnnotation(WebObject.class); 155 if (type != null) { 156 return TypeDescriptor.fromAnnotation(clazz, type); 157 } 158 WebAdapter ws = clazz.get().getAnnotation(WebAdapter.class); 159 if (ws != null) { 160 return AdapterDescriptor.fromAnnotation(clazz, ws); 161 } 162 return null; 163 } 164 165}