001 package opendreams.proxy;
002
003 import java.util.ArrayList;
004 import java.util.Calendar;
005 import java.util.HashSet;
006 import java.util.List;
007 import java.util.Set;
008
009 import tecgraf.ftc.common.exception.FailureException;
010 import tecgraf.ftc.common.logic.RemoteFileChannel;
011 import tecgraf.ftc.common.logic.RemoteFileChannelImpl;
012 import tecgraf.ftc.utils.Utils;
013 import tecgraf.openbus.data_service.DataDescription;
014 import tecgraf.openbus.data_service.DataKey;
015 import tecgraf.openbus.data_service.IHierarchicalDataService;
016 import tecgraf.openbus.data_service.Metadata;
017 import tecgraf.openbus.data_service.UnstructuredData;
018 import tecgraf.openbus.data_service.UnstructuredDataHelper;
019 import tecgraf.openbus.data_service.project.ProjectItemDescriptionImpl;
020 import tecgraf.openbus.project.ProjectItemDescription;
021 import tecgraf.openbus.project.ProjectItemDescriptionHelper;
022
023 /**
024 * Um projeto usado para escrever e ler arquivos usados na submissão de comandos
025 * pelo OpenDreams.
026 *
027 * @author Tecgraf PUC-Rio
028 */
029 public class Project {
030 private IHierarchicalDataService dataService;
031 private DataDescription projectDesc;
032 private String owner;
033 private byte[] currentDir;
034
035 /**
036 * Constrói uma representação do projeto.
037 *
038 * @param projectDesc descritor do projeto
039 * @param owner nome do usuário
040 * @param dataService serviço de projeto
041 */
042 Project(DataDescription projectDesc, String owner,
043 IHierarchicalDataService dataService) {
044 this.projectDesc = projectDesc;
045 this.dataService = dataService;
046 this.owner = owner;
047 this.currentDir = projectDesc.fKey;
048 }
049
050 /**
051 * Altera o diretório corrente para um outro que seja filho do diretório
052 * corrente.
053 *
054 * @param dirName nome do diretório filho do diretório corrente
055 * @return {@code true}, se o diretório corrente foi alterado ou {@code false}
056 * , caso contrário.
057 * @throws OpenDreamsException se ocorrer algum erro durante a mudança do
058 * diretório corrente.
059 *
060 */
061 public boolean changeDirectory(String dirName) throws OpenDreamsException {
062 return changeDirectory(dirName, false);
063 }
064
065 /**
066 * Altera o diretório corrente para um outro que seja filho do diretório
067 * corrente. Possibilita que o diretório filho seja criado, se não existir.
068 *
069 * @param dirName nome do diretório filho
070 * @param create se {@code true}, cria o diretório se não existir
071 * @return {@code true}, se o diretório corrente foi alterado ou {@code false}
072 * , caso contrário.
073 * @throws OpenDreamsException se ocorrer algum erro durante a mudança do
074 * diretório corrente.
075 */
076 public boolean changeDirectory(String dirName, boolean create)
077 throws OpenDreamsException {
078 byte[] fkey = this.find(dirName);
079 if (fkey != null) {
080 this.currentDir = fkey;
081 return true;
082 }
083 if (create) {
084 return createDirectory(dirName, true);
085 }
086 return false;
087 }
088
089 /**
090 * Altera o diretório corrente para o diretório pai.
091 *
092 * @return {@code true}, se o diretório corrente foi alterado ou {@code false}
093 * , caso contrário.
094 * @throws OpenDreamsException se o diretório corrente já estiver no próprio
095 * diretório do projeto ou se ocorrer algum erro na navegação para o
096 * diretório pai.
097 */
098 public boolean changeDirectoryUp() throws OpenDreamsException {
099 try {
100 if (this.currentDir.equals(projectDesc.fKey)) {
101 throw new OpenDreamsException(
102 "O diretório corrente é o próprio diretório do projeto");
103 }
104 DataDescription dataDescription = dataService.getParent(this.currentDir);
105 if (dataDescription == null) {
106 throw new OpenDreamsException("O diretório pai retornou null");
107 }
108 this.currentDir = dataDescription.fKey;
109 }
110 catch (Exception e) {
111 throw new OpenDreamsException("Erro na navegação para o diretório pai", e);
112 }
113 return true;
114 }
115
116 /**
117 * Cria um diretório filho do diretório corrente. Possibilita que o novo
118 * sub-diretório passe a ser o diretório corrente.
119 *
120 * @param dirName nome do diretório
121 * @param change se {@code true}, faz com o que o novo diretório seja o
122 * corrente
123 * @return {@code true}, se o diretório foi criado e {@code false}, caso
124 * contrário.
125 * @throws OpenDreamsException se ocorrer algum erro durante a criação do novo
126 * diretório.
127 */
128 public boolean createDirectory(String dirName, boolean change)
129 throws OpenDreamsException {
130 Set<String> views = new HashSet<String>();
131 views.add(ProjectItemDescriptionHelper.id());
132 long currentDate = Calendar.getInstance().getTimeInMillis();
133 ProjectItemDescription prototype =
134 new ProjectItemDescriptionImpl(dirName, views, new ArrayList<Metadata>(),
135 owner, null, null, null, 0, true, true, true, currentDate, currentDate);
136 try {
137 byte[] key = dataService.createData(currentDir, prototype);
138 if (change) {
139 this.currentDir = key;
140 }
141 return true;
142 }
143 catch (Exception e) {
144 throw new OpenDreamsException("Erro na criação do diretório " + dirName
145 + " no projeto " + projectDesc.fName, e);
146 }
147 }
148
149 /**
150 * Cria um diretório filho do diretório corrente.
151 *
152 * @param dirName nome do diretório
153 * @return {@code true}, se o diretório foi criado e {@code false}, caso
154 * contrário.
155 * @throws OpenDreamsException se ocorrer algum erro durante a criação do novo
156 * diretório.
157 */
158 public boolean createDirectory(String dirName) throws OpenDreamsException {
159 return createDirectory(dirName, false);
160 }
161
162 /**
163 * Obtém os dados de um arquivo que está no diretório corrente da área do
164 * projeto.
165 *
166 * @param fileName nome do arquivo
167 * @return o array com os bytes lidos
168 * @throws OpenDreamsException se ocorrer um erro na recuperação dos dados do
169 * arquivo.
170 */
171 public byte[] getDataFrom(String fileName) throws OpenDreamsException {
172 byte[] fileKey = this.find(fileName);
173 if (fileKey == null) {
174 throw new OpenDreamsException("Arquivo " + fileName + " não encontrado");
175 }
176 RemoteFileChannel rfc = null;
177 try {
178 UnstructuredData view =
179 (UnstructuredData) dataService.getDataView(fileKey,
180 UnstructuredDataHelper.id());
181 DataKey dataKey = new DataKey(view.fKey);
182 rfc =
183 new RemoteFileChannelImpl(dataKey.getDataId().getBytes(
184 Utils.CHARSET_ENCODING), view.fWritable, view.fHost, view.fPort,
185 view.fAccessKey);
186 rfc.open(true);
187 int fileSize = (int) rfc.getSize();
188 byte[] buffer = new byte[fileSize];
189 if (fileSize != 0) {
190 rfc.read(buffer);
191 }
192 return buffer;
193 }
194 catch (Exception e) {
195 throw new OpenDreamsException("Erro na leitura de um dado no projeto", e);
196 }
197 finally {
198 if (rfc != null) {
199 try {
200 rfc.close();
201 }
202 catch (FailureException e) {
203 throw new OpenDreamsException(
204 "Erro ao fechar o remote file channel na leitura de um dado no projeto",
205 e);
206 }
207 }
208 }
209 }
210
211 /**
212 * Cria um novo arquivo com o conteúdo passado como parâmetro.
213 *
214 * @param fileName nome do arquivo
215 * @param data o array com os bytes a serem escritos no arquivo
216 * @throws OpenDreamsException se o arquivo já existir ou se ocorrer algum
217 * erro durante a criação do arquivo.
218 */
219 public void createFile(String fileName, byte[] data)
220 throws OpenDreamsException {
221 byte[] fileKey = this.find(fileName);
222 if (fileKey != null) {
223 throw new OpenDreamsException("Arquivo " + fileName + " já existe");
224 }
225 RemoteFileChannel rfc = null;
226 try {
227 Set<String> views = new HashSet<String>();
228 views.add(ProjectItemDescriptionHelper.id());
229 long currentDate = Calendar.getInstance().getTimeInMillis();
230 ProjectItemDescription prototype =
231 new ProjectItemDescriptionImpl(fileName, views,
232 new ArrayList<Metadata>(), owner, null, null, null, 0, false, true,
233 true, currentDate, currentDate);
234 fileKey = dataService.createData(currentDir, prototype);
235 UnstructuredData view =
236 (UnstructuredData) dataService.getDataView(fileKey,
237 UnstructuredDataHelper.id());
238 DataKey dataKey = new DataKey(view.fKey);
239 rfc =
240 new RemoteFileChannelImpl(dataKey.getDataId().getBytes(
241 Utils.CHARSET_ENCODING), view.fWritable, view.fHost, view.fPort,
242 view.fAccessKey);
243 rfc.open(false);
244 rfc.write(data);
245 }
246 catch (Exception e) {
247 throw new OpenDreamsException("Erro na criação de um arquivo no projeto",
248 e);
249 }
250 finally {
251 if (rfc != null) {
252 try {
253 rfc.close();
254 }
255 catch (FailureException e) {
256 throw new OpenDreamsException(
257 "Erro ao fechar o remote file channel na criação de um arquivo no projeto",
258 e);
259 }
260 }
261 }
262 }
263
264 /**
265 * Remove um arquivo do projeto. O arquivo precisa existir.
266 *
267 * @param fileName nome do arquivo
268 * @throws OpenDreamsException se o arquivo não existir ou se ocorrer algum
269 * erro durante a remoção do arquivo.
270 */
271 public void removeFile(String fileName) throws OpenDreamsException {
272 byte[] fileKey = this.find(fileName);
273 if (fileKey == null) {
274 throw new OpenDreamsException("Arquivo " + fileName + " não existe");
275 }
276 try {
277 dataService.deleteData(fileKey);
278 }
279 catch (Exception e) {
280 throw new OpenDreamsException("Erro na remoção do arquivo " + fileName, e);
281 }
282 }
283
284 /**
285 * Verifica se um arquivo ou diretório existe no projeto.
286 *
287 * @param fileName nome do arquivo ou diretório
288 * @return {@code true}, se existe e {@code false}, caso contrário
289 * @throws OpenDreamsException se ocorrer algum erro no acesso ao arquivo
290 */
291 public boolean hasFile(String fileName) throws OpenDreamsException {
292 try {
293 return this.find(fileName) != null;
294 }
295 catch (Exception e) {
296 throw new OpenDreamsException("Erro na consulta se o arquivo " + fileName
297 + " existe", e);
298 }
299 }
300
301 /**
302 * Nome do projeto.
303 *
304 * @return o nome do projeto
305 */
306 public String getName() {
307 return projectDesc.fName;
308 }
309
310 /**
311 * Retorna a chave para um arquivo ou um diretório filho do diretório
312 * corrente.
313 *
314 * @param name nome do arquivo ou diretório procurado
315 * @return a chave do arquivo procurado ou null caso ele não exista
316 * @throws OpenDreamsException se ocorrer algum erro no acesso ao arquivo
317 */
318 private byte[] find(String name) throws OpenDreamsException {
319 byte[] fileKey = null;
320 DataDescription[] descriptions;
321 try {
322 descriptions = dataService.getChildren(currentDir);
323 for (DataDescription descr : descriptions) {
324 if (descr.fName.equals(name)) {
325 fileKey = descr.fKey;
326 break;
327 }
328 }
329 }
330 catch (Exception e) {
331 throw new OpenDreamsException(
332 "Erro na procura pelo arquivo ou diretório " + name, e);
333 }
334 return fileKey;
335 }
336
337 /**
338 * Retorna lista de nomes de arquivos e diretórios do diretório corrente.
339 *
340 * @return lista com OpenDreamsException de arquivos e diretórios do diretório
341 * corrente.
342 * @throws OpenDreamsException se ocorrer algum erro no acesso ao diretório
343 * corrente
344 */
345 public List<String> list() throws OpenDreamsException {
346 ArrayList<String> fileNames = new ArrayList<String>();
347 DataDescription[] descriptions;
348 try {
349 descriptions = dataService.getChildren(currentDir);
350 for (DataDescription descr : descriptions) {
351 fileNames.add(descr.fName);
352 }
353 }
354 catch (Exception e) {
355 throw new OpenDreamsException("Erro na listagem do diretório: "
356 + currentDir, e);
357 }
358 return fileNames;
359 }
360
361 /**
362 * Verifica se uma dada entrada é um diretório ou não.
363 *
364 * @param entryName o nome do diretório ou do arquivo
365 * @return {@code true} se é diretório, {@code false} se for arquivo
366 * @throws OpenDreamsException se ocorrer erro durante o acesso ao diretório
367 * corrente.
368 */
369 public boolean isDirectory(String entryName) throws OpenDreamsException {
370 try {
371 ProjectItemDescription descr =
372 (ProjectItemDescription) dataService.getDataDescription(this
373 .find(entryName));
374 return descr.fIsContainer;
375 }
376 catch (Exception e) {
377 throw new OpenDreamsException("Erro ao checar se " + entryName
378 + " é diretório.", e);
379 }
380 }
381 }