View Javadoc

1   package fr.in2p3.jsaga.impl.context;
2   
3   import fr.in2p3.jsaga.adaptor.base.defaults.Default;
4   import fr.in2p3.jsaga.adaptor.base.usage.Usage;
5   import fr.in2p3.jsaga.adaptor.security.*;
6   import fr.in2p3.jsaga.engine.factories.SecurityAdaptorFactory;
7   import fr.in2p3.jsaga.engine.session.SessionConfiguration;
8   import fr.in2p3.jsaga.impl.attributes.AbstractAttributesImpl;
9   import fr.in2p3.jsaga.impl.job.service.JobServiceImpl;
10  import org.apache.log4j.Logger;
11  import org.ogf.saga.SagaObject;
12  import org.ogf.saga.context.Context;
13  import org.ogf.saga.error.*;
14  
15  import java.io.ByteArrayOutputStream;
16  import java.io.FileNotFoundException;
17  import java.io.PrintStream;
18  import java.util.*;
19  
20  /* ***************************************************
21  * *** Centre de Calcul de l'IN2P3 - Lyon (France) ***
22  * ***             http://cc.in2p3.fr/             ***
23  * ***************************************************
24  * File:   ContextImpl
25  * Author: Sylvain Reynaud (sreynaud@in2p3.fr)
26  * Date:   17 sept. 2007
27  * ***************************************************
28  * Description:                                      */
29  /**
30   *
31   */
32  public class ContextImpl extends AbstractAttributesImpl implements Context {
33      public static final String URL_PREFIX = "UrlPrefix";
34      public static final String BASE_URL_INCLUDES = "BaseUrlIncludes";
35      public static final String BASE_URL_EXCLUDES = "BaseUrlExcludes";
36      public static final String JOB_SERVICE_ATTRIBUTES = "JobServiceAttributes";
37      public static final String DATA_SERVICE_ATTRIBUTES = "DataServiceAttributes";
38      public static final String RESOURCE_SERVICE_ATTRIBUTES = "ResourceServiceAttributes";
39  
40      private static Logger s_logger = Logger.getLogger(ContextImpl.class);
41      
42      private ContextAttributes m_attributes;
43      private SecurityAdaptor m_adaptor;
44      private SecurityCredential m_credential;
45      private WeakHashMap<JobServiceImpl,Object> m_jobServices;
46      private SessionConfiguration m_config;
47      private SecurityAdaptorFactory m_adaptorFactory;
48  
49      /** constructor */
50      public ContextImpl(String type, SessionConfiguration config, SecurityAdaptorFactory adaptorFactory) throws IncorrectStateException, TimeoutException, NoSuccessException {
51          super(null, true);  //not attached to a session, isExtensible=true
52          m_attributes = new ContextAttributes(this);
53          m_adaptor = null;
54          m_credential = null;
55          m_jobServices = new WeakHashMap<JobServiceImpl,Object>();
56          m_config = config;
57          m_adaptorFactory = adaptorFactory;
58          if (type!=null && !type.equals("")) {
59              try {
60                  this.setAttribute(Context.TYPE, type);
61              }
62              catch (IncorrectStateException e) {throw e;}
63              catch (TimeoutException e) {throw e;}
64              catch (NoSuccessException e) {throw e;}
65              catch (SagaException e) {throw new NoSuccessException(e);}
66          }
67      }
68  
69      /** clone */
70      public SagaObject clone() throws CloneNotSupportedException {
71          ContextImpl clone = (ContextImpl) super.clone();
72          clone.m_attributes = m_attributes;
73          clone.m_adaptor = m_adaptor;
74          clone.m_credential = m_credential;
75          clone.m_jobServices = m_jobServices;
76          clone.m_config = m_config;
77          clone.m_adaptorFactory = m_adaptorFactory;
78          return clone;
79      }
80  
81      ////////////////////////// override some AbstractAttributesImpl methods //////////////////////////
82  
83      /** override super.setAttribute() */
84      public void setAttribute(String key, String value) throws NotImplementedException, AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, IncorrectStateException, BadParameterException, DoesNotExistException, TimeoutException, NoSuccessException {
85          // set attribute
86          try {
87              m_attributes.getScalarAttribute(key).setValue(value);
88          } catch (DoesNotExistException e) {
89              super.setAttribute(key, value);
90          }
91          
92          // instanciate adaptor
93          if (Context.TYPE.equals(key)) {
94              // instanciate
95              m_adaptor = m_adaptorFactory.getSecurityAdaptor(value);
96  
97              // set PLUG-IN defaults
98              Default[] defaults = m_adaptor.getDefaults(new HashMap());
99              if (defaults != null) {
100                 for (int i=0; i<defaults.length; i++) {
101                     if (defaults[i].getValue() != null) {
102                         super.setAttribute(defaults[i].getName(), defaults[i].getValue());
103                     }
104                 }
105             }
106 
107             // set CONFIGURATION defaults (/jsaga-defaults/contexts)
108             if (m_config != null) {
109                 m_config.setDefaultContext(this);
110             }
111         }
112 
113         // reset credential
114         m_credential = null;
115     }
116 
117     /** override super.getAttribute() */
118     public String getAttribute(String key) throws NotImplementedException, AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, IncorrectStateException, DoesNotExistException, TimeoutException, NoSuccessException {
119         // get attribute
120         try {
121             return m_attributes.getScalarAttribute(key).getValue();
122         } catch (DoesNotExistException e) {
123             // try to get from credential
124             SecurityCredential credential = null;
125             try{credential=this.getCredential();} catch(IncorrectStateException e2){/* ignore "Missing attribute" */}
126             if (credential != null) {
127                 if (Context.USERID.equals(key)) {
128                     try {
129                         // try to get from credential
130                         return credential.getUserID();
131                     } catch (Exception e2) {
132                         throw new NoSuccessException(e2);
133                     }
134                 } else {
135                 	try{return credential.getAttribute(key);} catch(NotImplementedException e2){/* ignore "Unsupported attribute" */}
136                 }
137             }
138             // else try to get from parent class
139             try {
140                 return super.getAttribute(key);
141             } catch (DoesNotExistException dnee) {
142                 if (m_adaptor.getUsage().toString().contains(key)) {
143                     throw dnee;
144                 } else if (Context.USERID.equals(key)) {
145                     throw new IncorrectStateException("Attribute not yet initialized. Please first add context to a session.");
146                 } else {
147                     throw new NoSuccessException("Attribute not supported for this adaptor (or not yet initialized)");
148                 }
149             }
150         }
151     }
152 
153     /** override super.setVectorAttribute() */
154     public void setVectorAttribute(String key, String[] values) throws NotImplementedException, AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, IncorrectStateException, BadParameterException, DoesNotExistException, TimeoutException, NoSuccessException {
155         // set attribute
156         try {
157             m_attributes.getVectorAttribute(key).setValues(values);
158         } catch (DoesNotExistException e) {
159             super.setVectorAttribute(key, values);
160         }
161 
162         // reset credential
163         m_credential = null;
164     }
165 
166     /** override super.getVectorAttribute() */
167     public String[] getVectorAttribute(String key) throws NotImplementedException, AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, IncorrectStateException, DoesNotExistException, TimeoutException, NoSuccessException {
168         // get attribute
169         try {
170             return m_attributes.getVectorAttribute(key).getValues();
171         } catch (DoesNotExistException e) {
172             if (Context.USERID.equals(key)) {
173                 throw new IncorrectStateException("Operation not allowed on scalar attribute: "+key, this);
174             } else {
175                 // try to get from parent class
176                 return super.getVectorAttribute(key);
177             }
178         }
179     }
180 
181     private String getAttributeFromCredential(String key, SecurityCredential credential) throws NotImplementedException, DoesNotExistException, NoSuccessException {
182         try {
183             return credential.getAttribute(key);
184         } catch (NotImplementedException e) {
185             Usage usage = m_adaptor.getUsage();
186             if (usage!=null && usage.getKeys().contains(key)) {
187                 throw new DoesNotExistException("Attribute not set: "+key);
188             } else {
189                 throw new NotImplementedException("Attribute not supported: "+key);
190             }
191         }
192     }
193 
194     ///////////////////////////////////////// implementation /////////////////////////////////////////
195 
196     /**
197      * @see org.ogf.saga.session.Session
198      */
199     public void close() {
200         if (m_credential!= null) {
201             try {
202                 m_credential.close();
203             } catch (Exception e) {
204                 s_logger.warn("Failed to close security adaptor", e);
205             }
206             // reset credential
207             m_credential = null;
208         }
209     }
210 
211     /**
212      * This method is specific to JSAGA implementation.
213      */
214     public void destroy() throws IncorrectStateException, NoSuccessException {
215         if (m_adaptor== null) {
216             throw new IncorrectStateException("Attribute MUST be set before destroying context: "+Context.TYPE, this);
217         }
218         if (m_adaptor instanceof ExpirableSecurityAdaptor) {
219             try {
220                 ((ExpirableSecurityAdaptor) m_adaptor).destroySecurityAdaptor(
221                         super._getAttributesMap(), m_attributes.m_type.getValue());
222             } catch (Exception e) {
223                 throw new NoSuccessException(e);
224             }
225         }
226         // reset credential
227         m_credential = null;
228     }
229 
230     /**
231      * This method is specific to JSAGA implementation.
232      */
233     public String toString() {
234         ByteArrayOutputStream stream = new ByteArrayOutputStream();
235         PrintStream out = new PrintStream(stream);
236         if (m_credential!= null) {
237             try {
238                 m_credential.dump(out);
239             } catch (Exception e) {
240                 e.printStackTrace(out);
241             }
242         } else {
243             out.println("Not yet initialized");
244         }
245         out.close();
246         return stream.toString();
247     }
248 
249     /**
250      * This method is specific to JSAGA implementation.
251      */
252     public synchronized Class getCredentialClass() throws BadParameterException {
253         if (m_adaptor== null) {
254             throw new BadParameterException("Attribute MUST be set before using context: "+Context.TYPE, this);
255         }
256         return m_adaptor.getSecurityCredentialClass();
257     }
258 
259     /**
260      * This method is specific to JSAGA implementation.
261      */
262     public synchronized SecurityCredential getCredential() throws NotImplementedException, IncorrectStateException, TimeoutException, NoSuccessException {
263         if (m_adaptor== null) {
264             throw new IncorrectStateException("Attribute MUST be set before using context: "+Context.TYPE, this);
265         }
266 
267         return m_credential;
268     }
269 
270     public synchronized SecurityCredential createCredential() throws NotImplementedException, IncorrectStateException, TimeoutException, NoSuccessException {
271         Usage usage = m_adaptor.getUsage();
272         Map attributes = super._getAttributesMap();
273         
274         // Check attributes
275         if (!attributes.isEmpty()) {
276             Set<String> adaptorAttributes;
277             if (usage == null) {
278                 adaptorAttributes = new HashSet<String>();
279             } else {
280                 adaptorAttributes = usage.getKeys();
281             }
282             adaptorAttributes.addAll(Arrays.asList(Context.TYPE, ContextImpl.URL_PREFIX,
283                     ContextImpl.BASE_URL_INCLUDES, ContextImpl.BASE_URL_EXCLUDES,
284                     ContextImpl.JOB_SERVICE_ATTRIBUTES, ContextImpl.DATA_SERVICE_ATTRIBUTES,
285                     ContextImpl.RESOURCE_SERVICE_ATTRIBUTES));
286             Iterator i = attributes.keySet().iterator();
287             while (i.hasNext()) {
288                 Object attr = i.next();
289                 if (!adaptorAttributes.contains(attr)) {
290                     throw new IncorrectStateException("Invalid attribute: " + attr);
291                 }
292             }
293         }
294         
295         
296         int matching;
297         try {
298             matching = (usage!=null ? usage.getFirstMatchingUsage(attributes) : -1);
299         } catch(DoesNotExistException e) {
300             Usage missing = (usage!=null ? usage.getMissingValues(attributes) : null);
301             if (missing != null) {
302                 throw new IncorrectStateException("Missing attribute(s): "+missing.toString(), this);
303             } else {
304                 throw new NoSuccessException("[INTERNAL ERROR] Unexpected exception", this);
305             }
306         } catch (BadParameterException e) {
307             throw new IncorrectStateException("Invalid attribute(s): " + e.getMessage(), e);
308         } catch (FileNotFoundException e) {
309             // Should not happen
310             throw new IncorrectStateException("Invalid attribute(s): " + e.getMessage(), e);
311         }
312         m_credential = m_adaptor.createSecurityCredential(
313                 matching, attributes, m_attributes.m_type.getValue());
314         if (m_credential== null) {
315             throw new NotImplementedException("[INTERNAL ERROR] Method createSecurityCredential should never return 'null'");
316         }
317 
318         // reset the job services using this context
319         Set<JobServiceImpl> jobServices = new HashSet<JobServiceImpl>();
320         jobServices.addAll(m_jobServices.keySet());
321         new Thread(new JobServiceReset(jobServices, m_credential)).start();
322         return m_credential;
323     }
324     
325     /**
326      * This method is specific to JSAGA implementation.
327      */
328     public String getSchemeFromAlias(String alias) throws NotImplementedException, NoSuccessException {
329         String urlPrefix;
330         try{urlPrefix=m_attributes.m_urlPrefix.getValue()+"-";} catch(IncorrectStateException e){throw new NoSuccessException(e);}
331         if (alias.startsWith(urlPrefix)) {
332             return alias.substring(urlPrefix.length());
333         } else {
334             String scheme = m_attributes.m_baseUrlIncludes.getSchemeFromAlias(alias);
335             if (scheme != null) {
336                 return scheme;
337             } else {
338                 return alias;
339             }
340         }
341     }
342 
343     /**
344      * This method is specific to JSAGA implementation.
345      */
346     public Properties getServiceConfig(String serviceType, String scheme) {
347     	if (JOB_SERVICE_ATTRIBUTES.equals(serviceType)) {
348     		return m_attributes.m_jobServiceAttributes.getServiceConfig(scheme);
349     	} else if (DATA_SERVICE_ATTRIBUTES.equals(serviceType)) {
350     		return m_attributes.m_dataServiceAttributes.getServiceConfig(scheme);
351     	} else if (RESOURCE_SERVICE_ATTRIBUTES.equals(serviceType)) {
352     	    return m_attributes.m_resourceServiceAttributes.getServiceConfig(scheme);
353     	} else {
354     		return null;
355     	}
356     }
357 
358     /**
359      * This method is specific to JSAGA implementation.
360      */
361     public void throwIfConflictsWith(ContextImpl ref) throws NoSuccessException {
362         try {
363             m_attributes.m_baseUrlIncludes.throwIfConflictsWith(
364                     m_attributes.m_urlPrefix.getValue(),
365                     ref.m_attributes.m_urlPrefix.getValue(),
366                     ref.m_attributes.m_baseUrlIncludes,
367                     ref.m_attributes.m_baseUrlExcludes,
368                     m_attributes.m_baseUrlExcludes);
369         }
370         catch (NoSuccessException e) {throw e;}
371         catch (SagaException e) {throw new NoSuccessException(e);}
372     }
373 
374     /**
375      * This method is specific to JSAGA implementation.
376      */
377     public boolean matches(String url) {
378         // returns false if matches an excluded pattern
379         if (m_attributes.m_baseUrlExcludes.matches(url)) {
380             return false;
381         }
382         // returns true if matches an included pattern
383         return m_attributes.m_baseUrlIncludes.matches(url);
384     }
385 
386     /**
387      * This method is specific to JSAGA implementation.
388      */
389     public void setUrlPrefix(int position) throws NoSuccessException {
390         try {
391             if (m_attributes.m_urlPrefix.getValue() == null) {
392                 m_attributes.m_urlPrefix.setValue(m_attributes.m_type.getValue()+position);
393             }
394         }
395         catch (NoSuccessException e) {throw e;}
396         catch (SagaException e) {throw new NoSuccessException(e);}
397     }
398 
399     /**
400      * This method is specific to JSAGA implementation.
401      */
402     public synchronized void registerJobService(JobServiceImpl jobService) {
403         m_jobServices.put(jobService, new Object());
404     }
405 
406     /** This method is specific to JSAGA implementation. It should be used for debugging purpose only. */
407     public String getUsage() {
408         Usage usage = m_adaptor.getUsage();
409         if (usage != null) {
410             return usage.toString();
411         }
412         return null;
413     }
414     /** This method is specific to JSAGA implementation. It should be used for debugging purpose only. */
415     public String getDefault(String key) throws NotImplementedException, AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, IncorrectStateException, DoesNotExistException, TimeoutException, NoSuccessException {
416         // do not try to get attribute from credential
417         if (super.isVectorAttribute(key)) {
418             return Arrays.toString(super.getVectorAttribute(key));
419         } else {
420             return super.getAttribute(key);
421         }
422     }
423     /** This method is specific to JSAGA implementation. It should be used for debugging purpose only. */
424     public String getMissings() throws NotImplementedException, AuthenticationFailedException, AuthorizationFailedException, PermissionDeniedException, DoesNotExistException, IncorrectStateException, TimeoutException, NoSuccessException {
425         Map<String,String> defaults = new HashMap<String,String>();
426         for (String key : this.listAttributes()) {
427             defaults.put(key, this.getDefault(key));
428         }
429         Usage usage = m_adaptor.getUsage();
430         if (usage != null) {
431             Usage missing = usage.getMissingValues(defaults);
432             if (missing != null) {
433                 return missing.toString();
434             }
435         }
436         return null;
437     }
438 }