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", false);
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, false);
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.isDir()) {
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 }