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.OpenDreamsJobTemplateFactory;
023    import tecgraf.openbus.opendreams.OpenDreamsJobTemplateHelper;
024    import tecgraf.openbus.project.ProjectItemDescription;
025    import tecgraf.openbus.project.ProjectItemDescriptionHelper;
026    
027    /**
028     * O <code>OpenDreamsProxy</code> tem como objetivo encapsular os mecanismos de
029     * acesso ao OpenDreams. Faz o login no barramento e recupara as interfaces dos
030     * serviços usados pelo cliente desse barramento.
031     * 
032     * @author Tecgraf PUC-Rio
033     */
034    public class OpenDreamsProxy {
035      /**
036       * Nome do arquivo default com as propriedades para acesso ao OpenDreams.
037       */
038      public static String DEFAULT_PROPERTIES_FILE = "opendreams.properties";
039      /**
040       * Nome da propriedade que possui o nome do projeto configurado.
041       */
042      public static String PROJECT_PROPERTY = "opendreams.project.name";
043      /**
044       * O arquivo com a chave privada, quando a conexão é por certificado.
045       */
046      private InputStream privateKey;
047      /**
048       * O arquivo com o certificado digital, quando a conexão é por certificado.
049       */
050      private InputStream acsCertificate;
051      /**
052       * O proxy para o OpenBus
053       */
054      private OpenBusProxy proxy;
055    
056      /**
057       * Constrói um proxy para o serviço OpenDreams do OpenBus, usando as
058       * propriedades especificadas.
059       * 
060       * @param properties as propriedades previamente configuradas
061       * @throws OpenDreamsException se houve falha na carga das propriedades
062       */
063      public OpenDreamsProxy(Properties properties) throws OpenDreamsException {
064        try {
065          this.proxy = new OpenBusProxy(properties);
066        }
067        catch (OpenBusProxyException e) {
068          throw new OpenDreamsException("Erro na construção do OpenDreamsProxy", e);
069        }
070      }
071    
072      /**
073       * Constrói um proxy para o serviço OpenDreams do OpenBus, usando as
074       * propriedades do arquivo default de propriedades
075       * 
076       * @see #DEFAULT_PROPERTIES_FILE
077       * @throws OpenDreamsException se houve falha na carga das propriedades
078       */
079      public OpenDreamsProxy() throws OpenDreamsException {
080        try {
081          this.proxy = new OpenBusProxy(DEFAULT_PROPERTIES_FILE);
082        }
083        catch (OpenBusProxyException e) {
084          throw new OpenDreamsException("Erro na construção do OpenDreamsProxy", e);
085        }
086      }
087    
088      /**
089       * Atribui o arquivo com a chave privada para ser usada na conexão por
090       * certificado. Se esse arquivo não estiver definido, a conexão usa o nome do
091       * arquivo definido na propriedade openbus.acs.private.key. Esse método deve
092       * ter sido chamado antes de abrir o proxy, ou seja, antes de chamar o método
093       * {@link #init()}
094       * 
095       * @param privateKey o arquivo com chave privada usada para a conexão com o
096       *        barramento
097       */
098      public void setPrivatekey(InputStream privateKey) {
099        this.privateKey = privateKey;
100      }
101    
102      /**
103       * Atribui o arquivo com certificado público do serviço de acesso (ACS) , para
104       * ser usado na conexão por certificado. Se esse arquivo não estiver definido,
105       * a conexão usa o nome do arquivo definido na propriedade
106       * openbus.acs.certificate. Esse método deve ter sido chamado antes de abrir o
107       * proxy, ou seja, antes de chamar o método {@link #init()}
108       * 
109       * @param acsCertificate o arquivo com o certificado público do ACS, usado
110       *        para a conexão com o barramento
111       */
112      public void setACSCertificate(InputStream acsCertificate) {
113        this.acsCertificate = acsCertificate;
114      }
115    
116      /**
117       * Inicializa o contexto de acesso ao barramento, através de certificados.
118       * 
119       * @throws OpenDreamsException falha no acesso ao openbus
120       */
121      public void init() throws OpenDreamsException {
122        if (!isEnabled()) {
123          throw new OpenDreamsException("O proxy para o serviço opendreams não"
124            + " está habilitado. Verifique as propriedades openbus.enabled e "
125            + "opendreams.component.export");
126        }
127        try {
128          if (privateKey != null) {
129            proxy.setPrivatekey(privateKey);
130          }
131          if (acsCertificate != null) {
132            proxy.setACSCertificate(acsCertificate);
133          }
134          proxy.open();
135        }
136        catch (OpenBusProxyException e) {
137          throw new OpenDreamsException("Erro ao abrir o proxy do OpenBus", e);
138        }
139        registerFactories();
140      }
141    
142      /**
143       * Iniciliza o contexto de acesso ao barramento, através de login/senha.
144       * 
145       * @param user usuário LDAP
146       * @param password senha
147       * 
148       * @throws OpenDreamsException falha no acesso ao openbus
149       */
150      public void init(String user, String password) throws OpenDreamsException {
151        if (!isEnabled()) {
152          throw new OpenDreamsException("O proxy para o serviço opendreams não"
153            + " está habilitado. Verifique as propriedades openbus.enabled e "
154            + "opendreams.component.export");
155        }
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(JobInfoHelper.id(), new JobInfoFactory());
173        proxy.registerFactory(ProjectItemDescriptionHelper.id(),
174          new ProjectItemDescriptionFactory());
175        proxy.registerFactory(UnstructuredDataHelper.id(),
176          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")
189            .getFacet(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() throws OpenDreamsException {
204        try {
205          return IHierarchicalDataServiceHelper.narrow(proxy.getComponent(
206            "ProjectDataService").getFacet(IHierarchicalDataServiceHelper.id()));
207        }
208        catch (OpenBusProxyException e) {
209          throw new OpenDreamsException(
210            "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(),
268                dataService);
269            }
270          }
271        }
272        catch (ServiceFailure e) {
273          throw new OpenDreamsException("Falha no acesso ao serviço de projetos", e);
274        }
275        catch (DataAccessDenied e) {
276          throw new OpenDreamsException("Falha no acesso ao serviço de projetos", e);
277        }
278        return null;
279      }
280    
281      /**
282       * Obtém uma lista de proxies para os projetos do usuário.
283       * 
284       * @return lista de projetos, que pode ser vazia, caso o usuário não tenha
285       *         nenhum projeto.
286       * @throws OpenDreamsException se ocorrer um erro no acesso ao serviço de
287       *         projetos
288       */
289      public List<Project> getAllProjects() throws OpenDreamsException {
290        ArrayList<Project> ret = new ArrayList<Project>();
291    
292        IHierarchicalDataService dataService = this.getIDataService();
293        DataDescription[] rootDescList;
294        try {
295          rootDescList = dataService.getRoots();
296    
297          for (int i = 0; i < rootDescList.length; i++) {
298            DataDescription rootDesc = rootDescList[i];
299            if (!(rootDesc instanceof ProjectItemDescription)) {
300              throw new OpenDreamsException("Descritor inválido:"
301                + rootDesc.toString());
302            }
303            ret.add(new Project(rootDesc, proxy.getProperties().getUser(),
304              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
330            .addComponent("opendreams", IOpenDreamsHelper.id(), className);
331        }
332        catch (OpenBusProxyException e) {
333          throw new OpenDreamsException(
334            "Falha na publicação do componente opendreams", e);
335        }
336      }
337    
338      /**
339       * Verifica se o proxy está habilitado. Para o proxy estar habilitado é
340       * necessário que o barramento esteja habilitado (openbus.enabled) e o
341       * componente esteja habilitado (opendreams.enabled).
342       * 
343       * @return {@code true} se o proxy está habilitado ou {@code false} caso
344       *         contrário.
345       */
346      public boolean isEnabled() {
347        return proxy.isEnabled()
348          && proxy.getProperties().mayExportComponent("opendreams");
349      }
350    
351      /**
352       * Fecha o proxy
353       */
354      public void close() {
355        proxy.close();
356      }
357    
358      /**
359       * Altera o usuário para o qual a credencial está sendo delegada. Essa
360       * delegação é feita na thread.
361       * 
362       * @param user o login do usuário para o qual a credencial está sendo delegada
363       */
364      public void setThreadDelegate(String user) {
365        proxy.setThreadDelegate(user);
366      }
367    
368      /**
369       * Obtém as propriedades usadas para a configuração do proxy.
370       * 
371       * @return as propriedades usadas para configuração do proxy
372       */
373      public Properties getProperties() {
374        return proxy.getProperties();
375      }
376    }