1   /*
2    * Copyright 2000-2001,2004 The Apache Software Foundation.
3    * 
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    * 
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    * 
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  
17  /* 
18  
19   */
20  
21  package org.apache.wsrp4j.consumer.driver;
22  
23  import java.net.URL;
24  import java.util.Hashtable;
25  
26  import oasis.names.tc.wsrp.v1.intf.WSRP_v1_PortletManagement_PortType;
27  import oasis.names.tc.wsrp.v1.intf.WSRP_v1_Registration_PortType;
28  import oasis.names.tc.wsrp.v1.intf.WSRP_v1_ServiceDescription_PortType;
29  import oasis.names.tc.wsrp.v1.types.GetServiceDescription;
30  import oasis.names.tc.wsrp.v1.types.InvalidRegistrationFault;
31  import oasis.names.tc.wsrp.v1.types.ModifyRegistration;
32  import oasis.names.tc.wsrp.v1.types.PortletDescription;
33  import oasis.names.tc.wsrp.v1.types.RegistrationContext;
34  import oasis.names.tc.wsrp.v1.types.RegistrationData;
35  import oasis.names.tc.wsrp.v1.types.RegistrationState;
36  import oasis.names.tc.wsrp.v1.types.ReturnAny;
37  import oasis.names.tc.wsrp.v1.types.ServiceDescription;
38  import oasis.names.tc.wsrp.v1.wsdl.WSRPServiceLocator;
39  
40  import org.apache.wsrp4j.consumer.Producer;
41  import org.apache.wsrp4j.exception.ErrorCodes;
42  import org.apache.wsrp4j.exception.WSRPException;
43  import org.apache.wsrp4j.exception.WSRPXHelper;
44  import org.apache.wsrp4j.log.LogManager;
45  import org.apache.wsrp4j.log.Logger;
46  import org.apache.wsrp4j.util.ParameterChecker;
47  import org.apache.wsrp4j.util.StateChangedServiceImpl;
48  
49  /**
50   * A consumer representation of a WSRP-producer providing WSRP-portlets.
51   * Generally a producer can expose up to four WSRP-Interfaces. These interfaces are 
52   * Markup-, Service Description-,Registration- and WSRPPortlet Management Interface. Whereas
53   * the Registration- and Portlet Management Interface are optional.
54   * 
55   * @see Producer
56   * @author Stephan Laertz 
57   * @author Richard Jacob
58   **/
59  public class ProducerImpl extends StateChangedServiceImpl implements Producer {
60  
61      // ID and misc. infos
62      private String name = null;
63  
64      private String producerID = null;
65  
66      private String description = null;
67  
68      // URL's of the WSRP interfaces
69      private String registrationURL;
70  
71      private String serviceDescriptionURL;
72  
73      private String markupURL;
74  
75      private String portletManagementURL;
76  
77      // Registration
78      private boolean registrationRequired = false;
79  
80      private RegistrationContext registrationContext = null;
81  
82      private RegistrationData consumerRegData = null;
83  
84      // Service and portlet description
85      private ServiceDescription serviceDescription = null;
86  
87      private Hashtable portletDesc = null;
88  
89      // Stubs 
90      private WSRP_v1_ServiceDescription_PortType serviceDescriptionInterface = null;
91  
92      private WSRP_v1_Registration_PortType registrationInterface = null;
93  
94      private WSRP_v1_PortletManagement_PortType portletManagementInterface = null;
95  
96      // Logger and parameter checker
97      private Logger logger = null;
98  
99      private ParameterChecker checker = null;
100 
101     /**
102      * Default Constructor should not be used directly. But is 
103      * required for persistence support by castor.
104      **/
105     public ProducerImpl() {
106         this.portletDesc = new Hashtable();
107         logger = LogManager.getLogManager().getLogger(getClass());
108         checker = new ParameterChecker();
109 
110     }
111 
112     /**
113      * This constructor can be used to create a new producer object
114      **/
115     public ProducerImpl(String producerID, String markupURL,
116             String serviceDescriptionURL) throws WSRPException {
117 
118         this();
119         this.producerID = producerID;
120 
121         if (markupURL != null) {
122             this.markupURL = markupURL;
123         }
124         else {
125             WSRPXHelper.throwX(logger, Logger.ERROR, "init",
126                     ErrorCodes.MISSING_MARKUP_PORT);
127         }
128 
129         if (serviceDescriptionURL != null) {
130 
131             this.serviceDescriptionURL = serviceDescriptionURL;
132             initServiceDescInterface(serviceDescriptionURL);
133 
134         }
135         else {
136             WSRPXHelper.throwX(logger, Logger.ERROR, "init",
137                     ErrorCodes.MISSING_SERVCICE_DESC_PORT);
138         }
139 
140     }
141 
142     /**
143      * This constructor can be used to create a new producer object
144      **/
145     public ProducerImpl(String producerID, String markupURL,
146             String serviceDescriptionURL, String registrationURL,
147             String portletManagementURL, RegistrationData registrationData)
148             throws WSRPException {
149 
150         this(producerID, markupURL, serviceDescriptionURL);
151 
152         if (registrationURL != null) {
153 
154             initRegistrationInterface(registrationURL);
155             this.registrationURL = registrationURL;
156             this.consumerRegData = registrationData;
157         }
158 
159         if (portletManagementURL != null) {
160             this.portletManagementURL = portletManagementURL;
161             initPortletManagementInterface(portletManagementURL);
162         }
163     }
164 
165     /**
166      * Initialize the service description interface of the producer.
167      * 
168      * @param serviceDescriptionURL The URL of the producers service description interface
169      **/
170     public void initServiceDescInterface(String serviceDescriptionURL)
171             throws WSRPException {
172 
173         // just in case this has not been done before and for castor persistence
174         this.serviceDescriptionURL = serviceDescriptionURL;
175 
176         try {
177             WSRPServiceLocator serviceLocator = new WSRPServiceLocator();
178             serviceDescriptionInterface = serviceLocator
179                     .getWSRPServiceDescriptionService(new URL(
180                             serviceDescriptionURL));
181 
182         }
183         catch (javax.xml.rpc.ServiceException xmlEx) {
184 
185             WSRPXHelper.throwX(logger, Logger.ERROR,
186                     "initServiceDescInterface",
187                     ErrorCodes.INIT_OF_SERVICE_DESC_PORT_FAILED, xmlEx);
188 
189         }
190         catch (java.net.MalformedURLException urlEx) {
191 
192             WSRPXHelper.throwX(logger, Logger.ERROR,
193                     "initServiceDescInterface",
194                     ErrorCodes.INVALID_URL_OF_SERVICE_DESC_PORT, urlEx);
195 
196         }
197     }
198 
199     /**
200      * Initialize the registration interface of the producer.    
201      * 
202      * @param registrationURL The URL of the producers registration interface
203      **/
204     public void initRegistrationInterface(String registrationURL)
205             throws WSRPException {
206 
207         // just in case this has not been done before and for castor persistence
208         this.registrationURL = registrationURL;
209 
210         try {
211             WSRPServiceLocator serviceLocator = new WSRPServiceLocator();
212             registrationInterface = serviceLocator
213                     .getWSRPRegistrationService(new URL(registrationURL));
214 
215         }
216         catch (javax.xml.rpc.ServiceException xmlEx) {
217 
218             WSRPXHelper.throwX(logger, Logger.ERROR,
219                     "initRegistrationInterface",
220                     ErrorCodes.INIT_OF_REGISTRATION_PORT_FAILED, xmlEx);
221 
222         }
223         catch (java.net.MalformedURLException urlEx) {
224 
225             WSRPXHelper.throwX(logger, Logger.ERROR,
226                     "initRegistrationInterface",
227                     ErrorCodes.INVALID_URL_OF_REGISTRATION_PORT, urlEx);
228 
229         }
230     }
231 
232     /**
233      * Get the URL of the producers service description interface.
234      *
235      * @return URL of the service description interface.
236      **/
237     public String getServiceDescriptionInterfaceEndpoint() {
238         return this.serviceDescriptionURL;
239     }
240 
241     /**
242      * Set the URL of the producers service description interface.
243      *
244      * @param url URL of the service description interface.
245      **/
246     public void setServiceDescriptionInterfaceEndpoint(String url) {
247         serviceDescriptionURL = url;
248         stateChanged();
249     }
250 
251     /**
252      * Get the URL of the producers registration interface.
253      *
254      * @return URL of the registration interface.
255      **/
256     public String getRegistrationInterfaceEndpoint() {
257         return registrationURL;
258     }
259 
260     /**
261      * Set the URL of the producers registration interface.
262      *
263      * @param url URL of the registration interface.
264      **/
265     public void setRegistrationInterfaceEndpoint(String url) {
266         registrationURL = url;
267         stateChanged();
268     }
269 
270     /**      
271      * Get the ID of the producer.
272      *
273      * @return The ID of the producer
274      **/
275     public String getID() {
276         return producerID;
277     }
278 
279     /**
280      * Set the ID of the producer to he given value.
281      *
282      * @param id ID of the producer.
283      **/
284     public void setID(String id) {
285         producerID = id;
286         stateChanged();
287     }
288 
289     /**
290      * Get the name of the producer.               
291      *
292      * @return The name of the producer
293      **/
294     public String getName() {
295         return name;
296     }
297 
298     /**
299      * Set the name of the producer.
300      *
301      * @param name The name of the producer     
302      **/
303     public void setName(String name) {
304         this.name = name;
305         stateChanged();
306     }
307 
308     /**
309      * Get a description of the producer.
310      *
311      * @return A description of the producer
312      **/
313     public String getDescription() {
314         return this.description;
315     }
316 
317     /**
318      * Set a description of the producer.
319      *
320      * @param description Some descriptive information about the producer    
321      **/
322     public void setDescription(String description) {
323         this.description = description;
324         stateChanged();
325     }
326 
327     /**
328      * Indicates wether or not the producer requires consumer registration.
329      *
330      * @return True if consumer registration is required.
331      **/
332     public boolean isRegistrationRequired() {
333         return this.registrationRequired;
334     }
335 
336     /**
337      * Define if the producer requires in-band registration or not.
338      * 
339      * @param registrationRequired True if the producer requires in-band registration
340      **/
341     public void setIsRegistrationRequired(boolean registrationRequired) {
342         this.registrationRequired = registrationRequired;
343         stateChanged();
344     }
345 
346     /**
347      * Get the registration data the consumer uses to register at this producer.
348      * 
349      * @return The consumer registration data
350      **/
351     public RegistrationData getRegistrationData() {
352         return consumerRegData;
353     }
354 
355     /**
356      * Set the registration the consumer uses the register at this producer.
357      * 
358      * @param regData The registration data which is used to register at this producer
359      **/
360     public void setRegistrationData(RegistrationData regData) {
361         consumerRegData = regData;
362         stateChanged();
363     }
364 
365     /**
366      * Get the current registration context of the consumer registered at this producer or null
367      * if no registration is required or happend so far.
368      * 
369      * @return The current registration context of the consumer at this producer or null.
370      **/
371     public RegistrationContext getRegistrationContext() {
372         return this.registrationContext;
373     }
374 
375     /**
376      * Set the registration context.
377      * 
378      * @param registrationContext The registration context of a consumer registered at the producer.
379      **/
380     public void setRegistrationContext(RegistrationContext registrationContext) {
381         if (registrationContext != null) {
382             this.registrationContext = registrationContext;
383             stateChanged();
384         }
385     }
386 
387     /**
388      * Same as getServiceDescription(false)
389      **/
390     public ServiceDescription getServiceDescription() throws WSRPException {
391         return getServiceDescription(false);
392     }
393 
394     /**
395      * Get the service description of the producer
396      * 
397      * @param newRequest If set to true a new request is send to the producer otherwise a cached service description
398      * is used if available
399      * 
400      * @return Service description of the producer
401      **/
402     public ServiceDescription getServiceDescription(boolean newRequest)
403             throws WSRPException {
404         if (this.serviceDescription == null || newRequest) {
405             GetServiceDescription request = new GetServiceDescription();
406 
407             if (registrationContext != null) {
408                 request.setRegistrationContext(registrationContext);
409             }
410 
411             // TODO: Set desired locales which are supported by the consumer
412             //request.setDesiredLocales(new String[]{Constants.LOCALE_EN_US, Constants.LOCALE_DE_DE});
413             // for now request all locales
414             request.setDesiredLocales(null);
415 
416             ServiceDescription response = null;
417             try {
418 
419                 response = serviceDescriptionInterface
420                         .getServiceDescription(request);
421 
422                 if (response != null) {
423 
424                     try {
425 
426                         checker.check(response);
427 
428                     }
429                     catch (java.rmi.RemoteException wsrpFault) {
430 
431                         WSRPXHelper.handleWSRPFault(logger, wsrpFault);
432 
433                     }
434 
435                     if (registrationContext == null
436                             && response.isRequiresRegistration()) {
437                         register(consumerRegData);
438                         getServiceDescription(true);
439 
440                     }
441                     else {
442                         setServiceDescription(response);
443                     }
444 
445                 }
446                 else {
447 
448                     WSRPXHelper.throwX(logger, Logger.ERROR,
449                             "getServiceDescription",
450                             ErrorCodes.INVALID_SERVICE_DESCRIPTION);
451                 }
452 
453             }
454             catch (InvalidRegistrationFault invalidReg) {
455 
456                 // producer did not accept the registration
457                 // lets try it again
458                 register(consumerRegData);
459                 getServiceDescription(true);
460 
461             }
462             catch (java.rmi.RemoteException wsrpFault) {
463 
464                 WSRPXHelper.handleWSRPFault(logger, wsrpFault);
465 
466             }
467         }
468 
469         return this.serviceDescription;
470     }
471 
472     /**
473      * Get the portlet description of the portlet with the given handle from the
474      * service description or null if the producer doesn't offer an portlet with this handle
475      * in it's service description.
476      * 
477      * @param portletHandle The portlet handle of the portlet
478      * 
479      * @return The portlet description of the portlet with the given handle
480      **/
481     public PortletDescription getPortletDescription(String portletHandle)
482             throws WSRPException {
483 
484         PortletDescription desc = null;
485         if (portletHandle != null) {
486 
487             if (serviceDescription == null) {
488 
489                 // fetch a new portlet description from the producer
490                 getServiceDescription();
491             }
492 
493             desc = (PortletDescription) portletDesc.get(portletHandle);
494 
495             if (desc == null) {
496 
497                 WSRPXHelper.throwX(logger, Logger.ERROR,
498                         "getPortletDescription",
499                         ErrorCodes.INVALID_PORTLET_HANDLE);
500             }
501         }
502 
503         return desc;
504     }
505 
506     /**
507      * Set the consumer environment this producer is used.
508      * 
509      * @param consumerEnvironment The consumer environment of the consumer using
510      *                            the producer object.
511      **/
512     public void setServiceDescription(ServiceDescription serviceDescription) {
513         if (serviceDescription != null) {
514             this.serviceDescription = serviceDescription;
515             updatePortletDescriptions(serviceDescription);
516             setIsRegistrationRequired(serviceDescription
517                     .isRequiresRegistration());
518         }
519     }
520 
521     /**
522      * Add an portlet description to the producer. This portlet description is
523      * accessable through the portlet handle in the portlet description. If the
524      * producer has already an portlet description with this portlet handle than
525      * the old description will be overwritten.
526      * 
527      * @param portletDescription New portlet description 
528      **/
529     public void addPortletDescription(PortletDescription portletDescription) {
530         if (portletDescription != null) {
531             this.portletDesc.put(portletDescription.getPortletHandle(),
532                     portletDescription);
533         }
534     }
535 
536     private void updatePortletDescriptions(ServiceDescription serviceDescription) {
537         if (serviceDescription != null) {
538             PortletDescription[] offeredPortlets = serviceDescription
539                     .getOfferedPortlets();
540             if (offeredPortlets != null) {
541                 this.portletDesc.clear();
542 
543                 for (int i = 0; i < offeredPortlets.length; i++) {
544                     if (offeredPortlets[i] != null) {
545                         addPortletDescription(offeredPortlets[i]);
546                     }
547 
548                 }
549             }
550         }
551     }
552 
553     /**
554      * Method establishes a relationship between consumer and producer.
555      * 
556      * Note: A additional call of setRegistrationContext() is not neccesary 
557      *      
558      * @param registrationData Data which is used to register the consumer     
559      * 
560      * @return The registration context received by the producer      
561      **/
562     public RegistrationContext register(RegistrationData registrationData)
563             throws WSRPException {
564 
565         if (registrationData != null && this.registrationInterface != null) {
566 
567             try {
568 
569                 RegistrationContext regContext = registrationInterface
570                         .register(registrationData);
571                 checker.check(regContext, false);
572                 setRegistrationContext(regContext);
573 
574             }
575             catch (java.rmi.RemoteException wsrpFault) {
576 
577                 WSRPXHelper.handleWSRPFault(logger, wsrpFault);
578 
579             }
580 
581         }
582         else {
583 
584             // TODO: Either no registration data or producer does not support in-band registration
585         }
586 
587         return this.registrationContext;
588     }
589 
590     /**
591      * Can be used to modify the relationship between consumer and producer.
592      * 
593      * Note: A additional call of setRegistrationContext() is not neccesary
594      *     
595      * @param registrationData The new registration data                 
596      * 
597      * @return New registration context     
598      **/
599     public RegistrationState modifyRegistration(
600             RegistrationData registrationData) throws WSRPException {
601 
602         RegistrationState newState = null;
603 
604         try {
605             if (registrationData != null && this.registrationInterface != null) {
606 
607                 ModifyRegistration request = new ModifyRegistration();
608                 if (registrationContext != null) {
609                     request.setRegistrationContext(registrationContext);
610                 }
611                 request.setRegistrationData(registrationData);
612 
613                 newState = registrationInterface.modifyRegistration(request);
614 
615                 getRegistrationContext().setRegistrationState(
616                         newState.getRegistrationState());
617                 stateChanged();
618 
619             }
620             else {
621 
622                 // TODO: Either no data or producer does not support in-band registration
623             }
624         }
625         catch (java.rmi.RemoteException wsrpFault) {
626 
627             WSRPXHelper.handleWSRPFault(logger, wsrpFault);
628 
629         }
630 
631         return newState;
632     }
633 
634     /**
635      * End an existing consumer producer relationship and remove the registration context
636      * 
637      * @return Can be anything
638      **/
639     public ReturnAny deregister() throws WSRPException {
640         ReturnAny any = null;
641 
642         try {
643             if (registrationContext != null
644                     && this.registrationInterface != null) {
645 
646                 any = registrationInterface
647                         .deregister(this.registrationContext);
648                 registrationContext = null;
649                 registrationRequired = false;
650 
651                 stateChanged();
652 
653             }
654             else {
655                 // TODO: Either we aren't registered at the producer or 
656                 //      the producer does not support in-band registration
657             }
658 
659         }
660         catch (java.rmi.RemoteException wsrpFault) {
661 
662             WSRPXHelper.handleWSRPFault(logger, wsrpFault);
663         }
664 
665         return any;
666     }
667 
668     /**
669      * @see org.apache.wsrp4j.consumer.Producer#getMarkupInterfaceEndpoint()
670      */
671     public String getMarkupInterfaceEndpoint() {
672         return markupURL;
673     }
674 
675     /**
676      * @see org.apache.wsrp4j.consumer.Producer#setMarkupInterfaceEndpoint(java.lang.String)
677      */
678     public void setMarkupInterfaceEndpoint(String url) {
679         markupURL = url;
680         stateChanged();
681     }
682 
683     /**
684      * @see org.apache.wsrp4j.consumer.Producer#getPortletManagementInterfaceEndpoint()
685      */
686     public String getPortletManagementInterfaceEndpoint() {
687         return portletManagementURL;
688     }
689 
690     /**
691      * @see org.apache.wsrp4j.consumer.Producer#setPortletManagementInterfaceEndpoint(java.lang.String)
692      */
693     public void setPortletManagementInterfaceEndpoint(String url) {
694         portletManagementURL = url;
695         stateChanged();
696     }
697 
698     public void initPortletManagementInterface(String portletManagementURL)
699             throws WSRPException {
700         final String MN = "initPortletManagementInterface";
701 
702         // just in case this has not been done before and for castor persistence
703         this.portletManagementURL = portletManagementURL;
704 
705         try {
706             WSRPServiceLocator serviceLocator = new WSRPServiceLocator();
707             portletManagementInterface = serviceLocator
708                     .getWSRPPortletManagementService(new URL(
709                             portletManagementURL));
710         }
711         catch (javax.xml.rpc.ServiceException xmlEx) {
712 
713             WSRPXHelper.throwX(logger, Logger.ERROR, MN,
714                     ErrorCodes.INIT_OF_PORTLET_MGMT_PORT_FAILED, xmlEx);
715 
716         }
717         catch (java.net.MalformedURLException urlEx) {
718 
719             WSRPXHelper.throwX(logger, Logger.ERROR, MN,
720                     ErrorCodes.INVALID_URL_OF_PORTLET_MGMT_PORT, urlEx);
721 
722         }
723     }
724 
725     public WSRP_v1_PortletManagement_PortType getPortletManagementInterface() {
726         return portletManagementInterface;
727     }
728 
729     public WSRP_v1_Registration_PortType getRegistrationInterface() {
730         return registrationInterface;
731     }
732 
733     public WSRP_v1_ServiceDescription_PortType getServiceDescriptionInterface() {
734         return serviceDescriptionInterface;
735     }
736 
737     public boolean isPortletManagementInferfaceSupported() {
738         if (portletManagementURL != null) {
739             return true;
740         }
741         return false;
742     }
743 
744     public boolean isRegistrationInterfaceSupported() {
745         if (registrationURL != null) {
746             return true;
747         }
748         return false;
749     }
750 
751 }