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 }