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("(.+)\\.groovy");
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 Resource loadResource(String resourceId, ResourceKind resourceKind) {
071 Resource res = null;
072 try {
073
074 //
075 switch (resourceKind) {
076 case LIFECYCLE:
077 if ("login".equals(resourceId) || "logout".equals(resourceId)) {
078 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
079 long timestamp = Long.MIN_VALUE;
080 for (File path : dirs) {
081 File f = path.child(resourceId + ".groovy", false);
082 if (f != null) {
083 Resource sub = f.getResource();
084 if (sub != null) {
085 buffer.write(sub.getContent());
086 buffer.write('\n');
087 timestamp = Math.max(timestamp, sub.getTimestamp());
088 }
089 }
090 }
091 return new Resource(buffer.toByteArray(), timestamp);
092 }
093 break;
094 case COMMAND:
095 // Find the resource first, we find for the first found
096 for (File path : dirs) {
097 File f = path.child(resourceId + ".groovy", false);
098 if (f != null) {
099 res = f.getResource();
100 }
101 }
102 break;
103 case CONFIG:
104 String path = "/" + resourceId;
105 File file = confFS.get(Path.get(path));
106 if (file != null) {
107 res = loadConf(file);
108 }
109 }
110 } catch (IOException e) {
111 log.log(Level.WARNING, "Could not obtain resource " + resourceId, e);
112 }
113 return res;
114 }
115
116 /**
117 * List the resources id for a specific resource kind.
118 *
119 * @param kind the resource kind
120 * @return the resource ids
121 */
122 List<String> listResourceId(ResourceKind kind) {
123 switch (kind) {
124 case COMMAND:
125 SortedSet<String> all = new TreeSet<String>();
126 try {
127 for (File path : dirs) {
128 for (File file : path.children()) {
129 String name = file.getName();
130 Matcher matcher = p.matcher(name);
131 if (matcher.matches()) {
132 all.add(matcher.group(1));
133 }
134 }
135 }
136 }
137 catch (IOException e) {
138 e.printStackTrace();
139 }
140 all.remove("login");
141 all.remove("logout");
142 return new ArrayList<String>(all);
143 default:
144 return Collections.emptyList();
145 }
146 }
147
148 /**
149 * Refresh the fs system view. This is normally triggered by the periodic job but it can be manually
150 * invoked to trigger explicit refreshes.
151 */
152 void refresh() {
153 try {
154 File commands = cmdFS.get(Path.get("/"));
155 List<File> newDirs = new ArrayList<File>();
156 newDirs.add(commands);
157 for (File path : commands.children()) {
158 if (path.isDir()) {
159 newDirs.add(path);
160 }
161 }
162 dirs = newDirs;
163 }
164 catch (IOException e) {
165 e.printStackTrace();
166 }
167 }
168
169 /** . */
170 private static final byte[] SEPARATOR = System.getProperty("line.separator").getBytes();
171
172 public static Resource loadConf(File file) throws IOException {
173 // Special handling for property files
174 if (file.getName().endsWith(".properties")) {
175 Iterator<Resource> i = file.getResources().iterator();
176 if (i.hasNext()) {
177 ByteArrayOutputStream buffer = new ByteArrayOutputStream();
178 long timestamp = 0;
179 while (i.hasNext()) {
180 Resource resource = i.next();
181 byte[] bytes = resource.getContent();
182 buffer.write(bytes);
183 timestamp = Math.max(timestamp, resource.getTimestamp());
184 if (i.hasNext()) {
185 // Go to line
186 buffer.write(SEPARATOR);
187 // Cosmetic blank line
188 buffer.write(SEPARATOR);
189 }
190 }
191 return new Resource(buffer.toByteArray(), timestamp);
192 } else {
193 return null;
194 }
195 } else {
196 return file.getResource();
197 }
198 }
199 }