001 /* 002 * Copyright (C) 2012 eXo Platform SAS. 003 * 004 * This is free software; you can redistribute it and/or modify it 005 * under the terms of the GNU Lesser General Public License as 006 * published by the Free Software Foundation; either version 2.1 of 007 * the License, or (at your option) any later version. 008 * 009 * This software is distributed in the hope that it will be useful, 010 * but WITHOUT ANY WARRANTY; without even the implied warranty of 011 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 012 * Lesser General Public License for more details. 013 * 014 * You should have received a copy of the GNU Lesser General Public 015 * License along with this software; if not, write to the Free 016 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 017 * 02110-1301 USA, or see the FSF site: http://www.fsf.org. 018 */ 019 020 package org.crsh.plugin; 021 022 import org.crsh.vfs.FS; 023 import org.crsh.vfs.File; 024 import org.crsh.vfs.Path; 025 import org.crsh.vfs.Resource; 026 027 import java.io.ByteArrayOutputStream; 028 import java.io.IOException; 029 import java.util.ArrayList; 030 import java.util.Collections; 031 import java.util.Iterator; 032 import java.util.List; 033 import java.util.SortedSet; 034 import java.util.TreeSet; 035 import java.util.logging.Level; 036 import java.util.logging.Logger; 037 import java.util.regex.Matcher; 038 import java.util.regex.Pattern; 039 040 /** @author <a href="mailto:julien.viet@exoplatform.com">Julien Viet</a> */ 041 public class ResourceManager { 042 043 /** . */ 044 private static final Pattern p = Pattern.compile("([^.]+)\\.[^.]+"); 045 046 /** . */ 047 private static final Logger log = Logger.getLogger(ResourceManager.class.getName()); 048 049 /** . */ 050 private final FS cmdFS; 051 052 /** . */ 053 private final FS confFS; 054 055 /** . */ 056 private volatile List<File> dirs; 057 058 ResourceManager(FS cmdFS, FS confFS) { 059 this.cmdFS = cmdFS; 060 this.confFS = confFS; 061 } 062 063 /** 064 * Load a resource from the context. 065 * 066 * @param resourceId the resource id 067 * @param resourceKind the resource kind 068 * @return the resource or null if it cannot be found 069 */ 070 Iterable<Resource> loadResource(String resourceId, ResourceKind resourceKind) { 071 try { 072 switch (resourceKind) { 073 case LIFECYCLE: 074 if ("login".equals(resourceId) || "logout".equals(resourceId)) { 075 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 076 long timestamp = Long.MIN_VALUE; 077 for (File path : dirs) { 078 File f = path.child(resourceId + ".groovy"); 079 if (f != null) { 080 Resource sub = f.getResource(); 081 if (sub != null) { 082 buffer.write(sub.getContent()); 083 buffer.write('\n'); 084 timestamp = Math.max(timestamp, sub.getTimestamp()); 085 } 086 } 087 } 088 return Collections.singleton(new Resource(resourceId + ".groovy", buffer.toByteArray(), timestamp)); 089 } 090 break; 091 case COMMAND: 092 // Find the resource first, we find for the first found 093 for (File path : dirs) { 094 File f = path.child(resourceId); 095 if (f != null) { 096 return Collections.singleton(f.getResource()); 097 } 098 } 099 break; 100 case CONFIG: 101 String path = "/" + resourceId; 102 File file = confFS.get(Path.get(path)); 103 if (file != null) { 104 return Collections.singleton(loadConf(file)); 105 } 106 } 107 } catch (IOException e) { 108 log.log(Level.WARNING, "Could not obtain resource " + resourceId, e); 109 } 110 return Collections.emptyList(); 111 } 112 113 /** 114 * List the resources id for a specific resource kind. 115 * 116 * @param kind the resource kind 117 * @return the resource ids 118 */ 119 Iterable<String> listResourceId(ResourceKind kind) { 120 switch (kind) { 121 case COMMAND: 122 SortedSet<String> all = new TreeSet<String>(); 123 try { 124 for (File path : dirs) { 125 for (File file : path.children()) { 126 String fileName = file.getName(); 127 Matcher matcher = p.matcher(fileName); 128 if (matcher.matches()) { 129 String name = matcher.group(1); 130 if (!"login".equals(name) && !"logout".equals(name)) { 131 all.add(fileName); 132 } 133 } 134 } 135 } 136 } 137 catch (IOException e) { 138 e.printStackTrace(); 139 } 140 return all; 141 default: 142 return Collections.emptyList(); 143 } 144 } 145 146 /** 147 * Refresh the fs system view. This is normally triggered by the periodic job but it can be manually 148 * invoked to trigger explicit refreshes. 149 */ 150 void refresh() { 151 try { 152 File commands = cmdFS.get(Path.get("/")); 153 List<File> newDirs = new ArrayList<File>(); 154 newDirs.add(commands); 155 for (File path : commands.children()) { 156 if (path.children().iterator().hasNext()) { 157 newDirs.add(path); 158 } 159 } 160 dirs = newDirs; 161 } 162 catch (IOException e) { 163 e.printStackTrace(); 164 } 165 } 166 167 /** . */ 168 private static final byte[] SEPARATOR = System.getProperty("line.separator").getBytes(); 169 170 public static Resource loadConf(File file) throws IOException { 171 // Special handling for property files 172 if (file.getName().endsWith(".properties")) { 173 Iterator<Resource> i = file.getResources().iterator(); 174 if (i.hasNext()) { 175 ByteArrayOutputStream buffer = new ByteArrayOutputStream(); 176 long timestamp = 0; 177 while (i.hasNext()) { 178 Resource resource = i.next(); 179 byte[] bytes = resource.getContent(); 180 buffer.write(bytes); 181 timestamp = Math.max(timestamp, resource.getTimestamp()); 182 if (i.hasNext()) { 183 // Go to line 184 buffer.write(SEPARATOR); 185 // Cosmetic blank line 186 buffer.write(SEPARATOR); 187 } 188 } 189 return new Resource(file.getName(), buffer.toByteArray(), timestamp); 190 } else { 191 return null; 192 } 193 } else { 194 return file.getResource(); 195 } 196 } 197 }