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 }