001    package opendreams.proxy;
002    
003    import java.io.InputStream;
004    import java.util.ArrayList;
005    import java.util.List;
006    import java.util.Properties;
007    
008    import openbus.util.OpenBusProxy;
009    import openbus.util.OpenBusProxyException;
010    import tecgraf.openbus.DRMAA.JobInfoHelper;
011    import tecgraf.openbus.data_service.DataAccessDenied;
012    import tecgraf.openbus.data_service.DataDescription;
013    import tecgraf.openbus.data_service.IHierarchicalDataService;
014    import tecgraf.openbus.data_service.IHierarchicalDataServiceHelper;
015    import tecgraf.openbus.data_service.ServiceFailure;
016    import tecgraf.openbus.data_service.UnstructuredDataFactory;
017    import tecgraf.openbus.data_service.UnstructuredDataHelper;
018    import tecgraf.openbus.data_service.project.ProjectItemDescriptionFactory;
019    import tecgraf.openbus.opendreams.IOpenDreams;
020    import tecgraf.openbus.opendreams.IOpenDreamsHelper;
021    import tecgraf.openbus.opendreams.JobInfoFactory;
022    import tecgraf.openbus.opendreams.JobParameterFactory;
023    import tecgraf.openbus.opendreams.JobParameterHelper;
024    import tecgraf.openbus.opendreams.OpenDreamsJobTemplateFactory;
025    import tecgraf.openbus.opendreams.OpenDreamsJobTemplateHelper;
026    import tecgraf.openbus.project.ProjectItemDescription;
027    import tecgraf.openbus.project.ProjectItemDescriptionHelper;
028    
029    /**
030     * O <code>OpenDreamsProxy</code> tem como objetivo encapsular os mecanismos de
031     * acesso ao OpenDreams. Faz o login no barramento e recupara as interfaces dos
032     * serviços usados pelo cliente desse barramento.
033     * 
034     * @author Tecgraf PUC-Rio
035     */
036    public class OpenDreamsProxy {
037      /**
038       * Nome do arquivo default com as propriedades para acesso ao OpenDreams.
039       */
040      public static String DEFAULT_PROPERTIES_FILE = "opendreams.properties";
041      /**
042       * Nome da propriedade que possui o nome do projeto configurado.
043       */
044      public static String PROJECT_PROPERTY = "opendreams.project.name";
045      /**
046       * O arquivo com a chave privada, quando a conexão é por certificado.
047       */
048      private InputStream privateKey;
049      /**
050       * O arquivo com o certificado digital, quando a conexão é por certificado.
051       */
052      private InputStream acsCertificate;
053      /**
054       * O proxy para o OpenBus
055       */
056      private OpenBusProxy proxy;
057    
058      /**
059       * Constrói um proxy para o serviço OpenDreams do OpenBus, usando as
060       * propriedades especificadas.
061       * 
062       * @param properties as propriedades previamente configuradas
063       * @throws OpenDreamsException se houve falha na carga das propriedades
064       */
065      public OpenDreamsProxy(Properties properties) throws OpenDreamsException {
066        try {
067          this.proxy = new OpenBusProxy(properties);
068        }
069        catch (OpenBusProxyException e) {
070          throw new OpenDreamsException("Erro na construção do OpenDreamsProxy", e);
071        }
072      }
073    
074      /**
075       * Constrói um proxy para o serviço OpenDreams do OpenBus, usando as
076       * propriedades do arquivo default de propriedades
077       * 
078       * @see #DEFAULT_PROPERTIES_FILE
079       * @throws OpenDreamsException se houve falha na carga das propriedades
080       */
081      public OpenDreamsProxy() throws OpenDreamsException {
082        try {
083          this.proxy = new OpenBusProxy(DEFAULT_PROPERTIES_FILE);
084        }
085        catch (OpenBusProxyException e) {
086          throw new OpenDreamsException("Erro na construção do OpenDreamsProxy", e);
087        }
088      }
089      
090      /**
091       * Atribui o arquivo com a chave privada para ser usada na conexão por
092       * certificado. Se esse arquivo não estiver definido, a conexão usa o nome do
093       * arquivo definido na propriedade openbus.acs.private.key. Esse método deve
094       * ter sido chamado antes de abrir o proxy, ou seja, antes de chamar o método
095       * {@link #init()}
096       * 
097       * @param privateKey o arquivo com chave privada usada para a conexão com o
098       *        barramento
099       */
100      public void setPrivatekey(InputStream privateKey) {
101        this.privateKey = privateKey;
102      }
103    
104      /**
105       * Atribui o arquivo com certificado público do serviço de acesso (ACS) , para
106       * ser usado na conexão por certificado. Se esse arquivo não estiver definido,
107       * a conexão usa o nome do arquivo definido na propriedade
108       * openbus.acs.certificate. Esse método deve ter sido chamado antes de abrir o
109       * proxy, ou seja, antes de chamar o método {@link #init()}
110       * 
111       * @param acsCertificate o arquivo com o certificado público do ACS, usado
112       *        para a conexão com o barramento
113       */
114      public void setACSCertificate(InputStream acsCertificate) {
115        this.acsCertificate = acsCertificate;
116      }
117    
118      /**
119       * Inicializa o contexto de acesso ao barramento, através de certificados.
120       * 
121       * @throws OpenDreamsException falha no acesso ao openbus
122       */
123      public void init() throws OpenDreamsException {
124        if (!isEnabled())
125          throw new OpenDreamsException("O proxy para o serviço opendreams não" +
126            " está habilitado. Verifique as propriedades openbus.enabled e " +
127            "opendreams.component.export");
128        try {
129          if (privateKey!=null) {
130            proxy.setPrivatekey(privateKey);
131          }
132          if (acsCertificate!=null) {
133            proxy.setACSCertificate(acsCertificate);
134          }
135          proxy.open();
136        }
137        catch (OpenBusProxyException e) {
138          throw new OpenDreamsException("Erro ao abrir o proxy do OpenBus",e);
139        }
140        registerFactories();
141      }
142    
143      /**
144       * Iniciliza o contexto de acesso ao barramento, através de login/senha.
145       * 
146       * @param user usuário LDAP
147       * @param password senha
148       * 
149       * @throws OpenDreamsException falha no acesso ao openbus
150       */
151      public void init(String user, String password) throws OpenDreamsException {
152        if (!isEnabled())
153          throw new OpenDreamsException("O proxy para o serviço opendreams não" +
154            " está habilitado. Verifique as propriedades openbus.enabled e " +
155            "opendreams.component.export");
156        try {
157          proxy.open(user, password);
158        }
159        catch (OpenBusProxyException e) {
160          throw new OpenDreamsException("Erro ao abrir o proxy do OpenBus",e);
161        }
162        registerFactories();
163      }
164      
165      /**
166       * Faz o registro no ORB das fábricas necessárias para construção
167       * (marshalling) dos value types.
168       */
169      private void registerFactories() {
170        proxy.registerFactory(OpenDreamsJobTemplateHelper.id(),
171          new OpenDreamsJobTemplateFactory());
172        proxy.registerFactory(JobParameterHelper.id(), new JobParameterFactory());
173        proxy.registerFactory(JobInfoHelper.id(), new JobInfoFactory());
174        proxy.registerFactory(ProjectItemDescriptionHelper.id(),
175          new ProjectItemDescriptionFactory());
176        proxy.registerFactory(UnstructuredDataHelper.id(), new UnstructuredDataFactory());
177      }
178    
179      /**
180       * Obtém o objeto registrado no openbus que implementa a interface
181       * <code>IOpenDreams</code>
182       * 
183       * @return o serviço <code>IOpenDreams</code>
184       * @throws OpenDreamsException se o serviço não foi encontrado
185       */
186      public IOpenDreams getIOpenDreams() throws OpenDreamsException {
187        try {
188          return IOpenDreamsHelper.narrow(proxy.getComponent("opendreams").getFacet(
189            IOpenDreamsHelper.id()));
190        }
191        catch (OpenBusProxyException e) {
192          throw new OpenDreamsException("Erro ao recuperar o serviço opendreams",e);
193        }
194      }  
195    
196      /**
197       * Obtém o objeto registrado no openbus que implementa a interface
198       * <code>IOpenDreams</code>
199       * 
200       * @return o serviço <code>IOpenDreams</code>
201       * @throws OpenDreamsException se o serviço não foi encontrado
202       */
203      public IHierarchicalDataService getIDataService()
204        throws OpenDreamsException {
205        try {
206          return IHierarchicalDataServiceHelper.narrow(proxy.getComponent(
207            "ProjectDataService").getFacet(IHierarchicalDataServiceHelper.id()));
208        }
209        catch (OpenBusProxyException e) {
210          throw new OpenDreamsException("Erro ao recuperar o serviço ProjectDataService",e);
211        }
212      }
213    
214      /**
215       * Obtém um proxy para um projeto do usuário. O nome do projeto deve estar
216       * definido na propriedade <code>opendreams.project.name</code>. do arquivo de
217       * configuração.
218       * 
219       * @return um projeto.
220       * @throws OpenDreamsException se ocorrer um erro no acesso ao serviço de
221       *         projetos
222       */
223      public Project getProject() throws OpenDreamsException {
224        return getProject(getProjectName());
225      }
226    
227      /**
228       * Obtém o nome do projeto usado para acesso ao OpenDreams. Essa propriedade é
229       * opcional, mas
230       * 
231       * @return o nome do projeto
232       * @throws OpenDreamsException se o nome do projeto não estiver configurado
233       */
234      public String getProjectName() throws OpenDreamsException {
235        String projectName = proxy.getProperties().getProperty(PROJECT_PROPERTY);
236        if (projectName == null || projectName.trim().equals("")) {
237          throw new OpenDreamsException("Propriedade " + PROJECT_PROPERTY
238            + " não definida");
239        }
240        return projectName;
241      }
242    
243      /**
244       * Obtém um proxy para um projeto do usuário.
245       * 
246       * @param projectName nome do projeto
247       * 
248       * @return um projeto.
249       * @throws OpenDreamsException se ocorrer um erro no acesso ao serviço de
250       *         projetos
251       */
252      public Project getProject(String projectName) throws OpenDreamsException {
253        IHierarchicalDataService dataService = this.getIDataService();
254        DataDescription[] rootDescList;
255        try {
256          rootDescList = dataService.getRoots();
257          if (rootDescList.length < 1) {
258            throw new OpenDreamsException("O usuário não possui projetos");
259          }
260          for (int i = 0; i < rootDescList.length; i++) {
261            DataDescription rootDesc = rootDescList[i];
262            if (!(rootDesc instanceof ProjectItemDescription)) {
263              throw new OpenDreamsException("Descritor inválido:"
264                + rootDesc.toString());
265            }
266            if (rootDesc.fName.equals(projectName)) {
267              return new Project(rootDesc, proxy.getProperties().getUser(), dataService);
268            }
269          }
270        }
271        catch (ServiceFailure e) {
272          throw new OpenDreamsException("Falha no acesso ao serviço de projetos",
273            e);
274        }
275        catch (DataAccessDenied e) {
276          throw new OpenDreamsException("Falha no acesso ao serviço de projetos",
277            e);
278        }
279        return null;
280      }
281    
282      /**
283       * Obtém uma lista de proxies para os projetos do usuário.
284       * 
285       * @return lista de projetos, que pode ser vazia, caso o usuário não tenha
286       *         nenhum projeto.
287       * @throws OpenDreamsException se ocorrer um erro no acesso ao serviço de
288       *         projetos
289       */
290      public List<Project> getAllProjects() throws OpenDreamsException {
291        ArrayList<Project> ret = new ArrayList<Project>();
292    
293        IHierarchicalDataService dataService = this.getIDataService();
294        DataDescription[] rootDescList;
295        try {
296          rootDescList = dataService.getRoots();
297    
298          for (int i = 0; i < rootDescList.length; i++) {
299            DataDescription rootDesc = rootDescList[i];
300            if (!(rootDesc instanceof ProjectItemDescription)) {
301              throw new OpenDreamsException("Descritor inválido:"
302                + rootDesc.toString());
303            }
304            ret.add(new Project(rootDesc, proxy.getProperties().getUser(), dataService));
305          }
306        }
307        catch (ServiceFailure e) {
308          throw new OpenDreamsException(
309            "Falha no acesso ao serviço de projetos (getAllProjects())", e);
310        }
311        catch (DataAccessDenied e) {
312          throw new OpenDreamsException(
313            "Falha no acesso ao serviço de projetos (getAllProjects())", e);
314        }
315        return ret;
316      }
317    
318      /**
319       * Fecha a conexão com o openbus.
320       * 
321       * @param className nome canônico da classe que implementa o serviço
322       * @return {@code true} caso o componente seja registrado ou {@code false},
323       *         caso contrário.
324       * @throws OpenDreamsException Caso o proxy não esteja aberto para fazer o
325       *         registro das ofertas de serviço.
326       */
327      public boolean addComponent(String className) throws OpenDreamsException {
328        try {
329          return proxy.addComponent("opendreams", IOpenDreamsHelper.id(), className);
330        }
331        catch (OpenBusProxyException e) {
332          throw new OpenDreamsException(
333            "Falha na publicação do componente opendreams", e);
334        }
335      }
336    
337      /**
338       * Verifica se o proxy está habilitado.
339       * Para o proxy estar habilitado é necessário que o barramento esteja 
340       * habilitado (openbus.enabled) e o componente esteja habilitado (opendreams.enabled).
341       * @return {@code true} se o proxy está habilitado ou
342       *         {@code false} caso contrário.
343       */
344      public boolean isEnabled() {
345        return proxy.isEnabled()
346          && proxy.getProperties().mayExportComponent("opendreams");
347      }
348      
349      /**
350       * Fecha o proxy
351       */
352      public void close() {
353        proxy.close();   
354      }
355      
356      /**
357       * Altera o usuário para o qual a credencial está sendo delegada.
358       * Essa delegação é feita na thread.
359       * @param user o login do usuário para o qual a credencial está sendo delegada
360       */
361      public void setThreadDelegate (String user) {
362        proxy.setThreadDelegate(user);
363      }
364      
365      /**
366       * Obtém as propriedades usadas para a configuração do proxy.
367       * @return as propriedades usadas para configuração do proxy
368       */
369      public Properties getProperties () {
370        return proxy.getProperties();
371      }
372    }