001    package opendreams.proxy;
002    
003    import java.util.ArrayList;
004    import java.util.Calendar;
005    import java.util.HashSet;
006    import java.util.Set;
007    
008    import tecgraf.ftc.common.logic.RemoteFileChannel;
009    import tecgraf.ftc.common.logic.RemoteFileChannelImpl;
010    import tecgraf.ftc.utils.Utils;
011    import tecgraf.openbus.data_service.DataDescription;
012    import tecgraf.openbus.data_service.DataKey;
013    import tecgraf.openbus.data_service.IHierarchicalDataService;
014    import tecgraf.openbus.data_service.Metadata;
015    import tecgraf.openbus.data_service.UnstructuredData;
016    import tecgraf.openbus.data_service.UnstructuredDataHelper;
017    import tecgraf.openbus.project.ProjectItemDescription;
018    import tecgraf.openbus.project.ProjectItemDescriptionHelper;
019    import tecgraf.openbus.project.ProjectItemDescriptionImpl;
020    
021    /**
022     * Um projeto usado para escrever e ler arquivos usados na submissão de comandos
023     * pelo OpenDreams.
024     * 
025     * @author Tecgraf PUC-Rio
026     */
027    public class Project {
028      private IHierarchicalDataService dataService;
029      private DataDescription projectDesc;
030      private String owner;
031      private byte[] currentDir;
032    
033      /**
034       * Constrói uma representação do projeto.
035       * 
036       * @param projectDesc descritor do projeto
037       * @param owner nome do usuário 
038       * @param dataService serviço de projeto
039       */
040      Project(DataDescription projectDesc, String owner,
041        IHierarchicalDataService dataService) {
042        this.projectDesc = projectDesc;
043        this.dataService = dataService;
044        this.owner = owner;
045        this.currentDir = projectDesc.fKey;
046      }
047    
048      /**
049       * Altera o diretório corrente.
050       * @param dirName nome do diretório
051       * @return verdadeiro, se já existe um diretório com o nome fornecido ou falso, caso contrário.
052       * @throws OpenDreamsException
053       */
054      public boolean changeDirectory(String dirName) throws OpenDreamsException {
055        return changeDirectory(dirName, false);
056      }
057    
058      /**
059       * Altera o diretório para um outro que seja filho do diretório corrente.
060       * @param dirName nome do diretório filho
061       * @param create se verdadeiro, cria o diretório se não existir
062       * @return verdadeiro, se o diretório corrente foi alterado ou falso, caso 
063       * contrário.
064       * @throws OpenDreamsException
065       */
066      public boolean changeDirectory(String dirName, boolean create)
067        throws OpenDreamsException {
068        byte[] fkey = this.find(dirName);
069        if (fkey != null) {
070          this.currentDir = fkey;
071          return true;
072        }
073        if (create) {
074          return createDirectory(dirName, true);
075        }
076        return false;
077      }
078    
079      /**
080       * Cria um diretório filho do diretório corrente.
081       * @param dirName nome do diretório
082       * @param change se verdadeiro, faz com o que o novo diretório seja o corrente
083       * @return verdadeiro, se o diretório foi criado e falso, caso contrário.
084       * @throws OpenDreamsException 
085       */
086      public boolean createDirectory(String dirName, boolean change)
087        throws OpenDreamsException {
088        Set<String> views = new HashSet<String>();
089        views.add(ProjectItemDescriptionHelper.id());
090        long currentDate = Calendar.getInstance().getTimeInMillis();
091        ProjectItemDescription prototype =
092          new ProjectItemDescriptionImpl(dirName, views, new ArrayList<Metadata>(),
093            owner, null, null, null, 0, true, true, true, currentDate, currentDate);
094        try {
095          byte[] key = dataService.createData(currentDir, prototype);
096          if (change) {
097            this.currentDir = key;
098          }
099          return true;
100        }
101        catch (Exception e) {
102          throw new OpenDreamsException("Erro na criação do diretório " + dirName
103            + " no projeto " + projectDesc.fName, e);
104        }
105      }
106    
107      /**
108       * Cria um diretório filho do diretório corrente.
109       * @param dirName nome do diretório
110       * @return verdadeiro, se o diretório foi criado e falso, caso contrário.
111       * @throws OpenDreamsException 
112       */
113      public boolean createDirectory(String dirName) throws OpenDreamsException {
114        return createDirectory(dirName, false);
115      }
116    
117      /**
118       * Obtém os dados de um arquivo que está no diretório corrente da área
119       * do projeto.
120       * @param fileName nome do arquivo
121       * @return o array com os bytes lidos
122       * @throws OpenDreamsException
123       */
124      public byte[] getDataFrom(String fileName) throws OpenDreamsException {
125        byte[] fileKey = this.find(fileName);
126        if (fileKey == null) {
127          throw new OpenDreamsException("Arquivo " + fileName + " não encontrado");
128        }
129        try {
130          UnstructuredData view =
131            (UnstructuredData) dataService.getDataView(fileKey,
132              UnstructuredDataHelper.id());
133          DataKey dataKey = new DataKey(view.fKey);
134          RemoteFileChannel rfc =
135            new RemoteFileChannelImpl(dataKey.getDataId().getBytes(
136              Utils.CHARSET_ENCODING), view.fWritable, view.fHost, view.fPort,
137              view.fAccessKey);
138          rfc.open(true);
139          int fileSize = (int) rfc.getSize();
140          byte[] buffer = new byte[fileSize];
141          rfc.read(buffer);
142          rfc.close();
143          return buffer;
144        }
145        catch (Exception e) {
146          throw new OpenDreamsException("Erro na leitura de um dado no projeto", e);
147        }
148      }
149      
150      /**
151       * Grava os dados em um arquivo que está no diretório corrente da área
152       * do projeto.
153       * @param fileName nome do arquivo
154       * @param data o array com os bytes a serem escritos no arquivo
155       * @throws OpenDreamsException
156       */
157      public void createFile (String fileName, byte[] data) throws OpenDreamsException {
158        byte[] fileKey = this.find(fileName);
159        if (fileKey != null) {
160          throw new OpenDreamsException("Arquivo " + fileName + " já existe");
161        }
162        try {
163          Set<String> views = new HashSet<String>();
164          views.add(ProjectItemDescriptionHelper.id());
165          long currentDate = Calendar.getInstance().getTimeInMillis();
166          ProjectItemDescription prototype =
167            new ProjectItemDescriptionImpl(fileName, views, new ArrayList<Metadata>(),
168              owner, null, null, null, 0, false, true, true, currentDate, currentDate);
169          fileKey = dataService.createData(currentDir, prototype);
170          UnstructuredData view =
171            (UnstructuredData) dataService.getDataView(fileKey,
172              UnstructuredDataHelper.id());
173          DataKey dataKey = new DataKey(view.fKey);
174          RemoteFileChannel rfc =
175            new RemoteFileChannelImpl(dataKey.getDataId().getBytes(
176              Utils.CHARSET_ENCODING), view.fWritable, view.fHost, view.fPort,
177              view.fAccessKey);
178          rfc.open(false);
179          rfc.write(data);
180          rfc.close();
181        }
182        catch (Exception e) {
183          throw new OpenDreamsException("Erro na criação de um arquivo no projeto", e);
184        }
185      }
186      
187      /**
188       * Remove um arquivo do projeto. O arquivo precisa existir.
189       * @param fileName nome do arquivo
190       * @throws OpenDreamsException
191       */
192      public void removeFile(String fileName) throws OpenDreamsException {
193        byte[] fileKey = this.find(fileName);
194        if (fileKey == null) {
195          throw new OpenDreamsException("Arquivo " + fileName + " não existe");
196        }
197        try {
198          dataService.deleteData(fileKey);
199        }
200        catch (Exception e) {
201          throw new OpenDreamsException("Erro na remoção do arquivo " + fileName, e);
202        }
203      }
204      
205      /**
206       * Verifica se um arquivo ou diretório existe no projeto.
207       * @param fileName nome do arquivo ou diretório
208       * @return verdadeiro, se existe e falso, caso contrário
209       * @throws OpenDreamsException
210       */
211      public boolean hasFile (String fileName) throws OpenDreamsException {
212        try {
213        return this.find(fileName)!=null;
214        }
215        catch (Exception e) {
216          throw new OpenDreamsException("Erro na consulta se o arquivo " + fileName + " existe", e);
217        }
218      }
219    
220      /**
221       * Nome do projeto.
222       * @return o nome do projeto
223       */
224      public String getName() {
225        return projectDesc.fName;
226      }
227    
228      /**
229       * Retorna a chave para um arquivo ou um diretório filho do diretório corrente.
230       * @param name nome do arquivo ou diretório procurado
231       * @return a chave do arquivo procurado ou null caso ele não exista
232       * @throws OpenDreamsException
233       */
234      private byte[] find(String name) throws OpenDreamsException {
235        byte[] fileKey = null;
236        DataDescription[] descriptions;
237        try {
238          descriptions = dataService.getChildren(currentDir);
239          for (DataDescription descr : descriptions) {
240            if (descr.fName.equals(name)) {
241              fileKey = descr.fKey;
242              break;
243            }
244          }
245        }
246        catch (Exception e) {
247          throw new OpenDreamsException(
248            "Erro na procura pelo arquivo ou diretório " + name, e);
249        }
250        return fileKey;
251      }
252    }