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 }