Academic Tutorials



English | French | Portugese | German | Italian
Home Advertise Payments Recommended Websites Interview Questions FAQs
News Source Codes E-Books Downloads Jobs Web Hosting
Chats

Weblogic Tutorial
WebLogic Tutorial Introduction
The WebLogic Workshop Development Environment
Developing Applications
Applications and Projects
Workshop File Types
Debugging Your Application
Managing the Build Process
Compile a Single Java File
Source Control Systems
Message Logging
Working with Java Controls
Developing Web Applications
Designing Asynchronous Interfaces
Handling XML with XMLBeans
Building Integration Applications
Building Portal Applications
Developing Enterprise JavaBeans
The Life Cycle of an Entity Bean
Session Beans
Developing Message-Driven Beans
WebLogic Workshop Security Overview
Deploying an Application

HTML Tutorials
HTML Tutorial
XHTML Tutorial
CSS Tutorial
TCP/IP Tutorial
CSS 1.0
CSS 2.0
HLML
XML Tutorials
XML Tutorial
XSL Tutorial
XSLT Tutorial
DTD Tutorial
Schema Tutorial
XForms Tutorial
XSL-FO Tutorial
XML DOM Tutorial
XLink Tutorial
XQuery Tutorial
XPath Tutorial
XPointer Tutorial
RDF Tutorial
SOAP Tutorial
WSDL Tutorial
RSS Tutorial
WAP Tutorial
Web Services Tutorial
Browser Scripting
JavaScript Tutorial
VBScript Tutorial
DHTML Tutorial
HTML DOM Tutorial
WMLScript Tutorial
E4X Tutorial
Server Scripting
ASP Tutorial
PERL Tutorial
SQL Tutorial
ADO Tutorial
CVS
Python
Apple Script
PL/SQL Tutorial
SQL Server
PHP
.NET (dotnet)
Microsoft.Net
ASP.Net
.Net Mobile
C# : C Sharp
ADO.NET
VB.NET
VC++
Multimedia
SVG Tutorial
Flash Tutorial
Media Tutorial
SMIL Tutorial
Photoshop Tutorial
Gimp Tutorial
Matlab
Gnuplot Programming
GIF Animation Tutorial
Scientific Visualization Tutorial
Graphics
Web Building
Web Browsers
Web Hosting
W3C Tutorial
Web Building
Web Quality
Web Semantic
Web Careers
Weblogic Tutorial
SEO
Web Site Hosting
Domain Name
Java Tutorials
Java Tutorial
JSP Tutorial
Servlets Tutorial
Struts Tutorial
EJB Tutorial
JMS Tutorial
JMX Tutorial
Eclipse
J2ME
JBOSS
Programming Langauges
C Tutorial
C++ Tutorial
Visual Basic Tutorial
Data Structures Using C
Cobol
Assembly Language
Mainframe
Forth Programming
Lisp Programming
Pascal
Delphi
Fortran
OOPs
Data Warehousing
CGI Programming
Emacs Tutorial
Gnome
ILU
Soft Skills
Communication Skills
Time Management
Project Management
Team Work
Leadership Skills
Corporate Communication
Negotiation Skills
Database Tutorials
Oracle
MySQL
Operating System
BSD
Symbian
Unix
Internet
IP-Masquerading
IPC
MIDI
Software Testing
Testing
Firewalls
SAP Module
ERP
ABAP
Business Warehousing
SAP Basis
Material Management
Sales & Distribution
Human Resource
Netweaver
Customer Relationship Management
Production and Planning
Networking Programming
Corba Tutorial
Networking Tutorial
Microsoft Office
Microsoft Word
Microsoft Outlook
Microsoft PowerPoint
Microsoft Publisher
Microsoft Excel
Microsoft Front Page
Microsoft InfoPath
Microsoft Access
Accounting
Financial Accounting
Managerial Accounting
Network Sites


Developing Message-Driven Beans


Previoushome Next






Developing Message-Driven Beans


An message-driven EJB is used to receive and process asynchronous messages using JMS. Message-driven EJBs are never directly invoked by other EJBs. However, they in turn can invoke methods of session and entity beans and send JMS messages to be processed by other message-driven EJBs. The topics listed below discuss development of message-driven beans.

A D V E R T I S E M E N T

 


What are Message-Driven Beans?


Message-driven beans are server-side objects used only to process JMS messages. These beans are stateless, in that each method invocation is independent from the next. Unlike session and entity beans, message-driven beans are not invoked by other beans or client applications. Instead a message-driven bean responds to a JMS message.

Because message-driven beans are not invoked by other EJBs or clients, these beans do not have interfaces. For each message-driven bean a single method, onMessage, is defined to process a JMS message. Although message-driven beans cannot be invoked by other EJBs, they can in turn invoke other EJBs. Also, message-driven beans can send JMS messages. As with the other types of EJBs, the EJB container is responsible for managing the beans environment, including making enough instances available for processing and message-acknowledgement.


Asynchronous and Concurrent Processing


A core feature of message-driven beans is the notion of asynchronous processing. A client application can send a JMS message to execute a certain business task. After the message has been sent, the client application can continue right away and does not have to wait for the JMS message to be received and processed. This is especially helpful when the business task is complex, requires the use of entity (and session) beans, and takes a long time to complete. In contrast, if the same client application were to use a session bean to execute a certain business task, it would have to wait until the session bean method completed and returned control to the client application. The message fa�ade design pattern formalizes this use of message-driven beans as an intermediary between client applications and entity beans to achieve asynchrony. An example of this pattern is shown in the Message-Driven Bean Sample.

Another important feature of message-driven beans is that JMS messages are processed concurrently. That is, although each bean instance handles a message at a time, the EJB container takes care of creating enough bean instances to handle the message load at a given moment. In WebLogic you can set the initial number and max number of bean instances created by the container. For more information, see the @ejbgen:message-driven Annotation.

Because message-driven beans are stateless and processing of JMS messages occurs in an asynchronous message, there is no guarantee that messages are processed in the order they were sent. Therefore, sending multiple messages such that one message is dependent on the successful processing of another message might cause unexpected results. Instead, you should reconsider the granularity of your business task such that one message can initiate its execution, possibly by handling one piece of the task, and then sending a JMS message to be processed by another message-driven bean for the remainder of the business task.


Topics and Queues


A message-driven bean listens to a particular channel for JMS messages. There are two types of channels, namely topics and queues. Topics implement the publish-and-subscribe messaging model, in which a given message can be received by many different subscribers, that is, many different message-driven bean classes (not instances) listening to the same topic. In contrast, queues implement the point-to-point messaging model, in which a given message is received by exactly one message-driven bean class, even when multiple classes are listening to this queue.


The Life Cycle of a Message-Driven Bean


The EJB container is responsible for creating a pool of message-driven bean instances. When it creates an instance, it calls the setMessageDrivenContext() and the ejbCreate() methods. At this point the message-driven bean is ready to receive messages. When a bean instance is processing a JMS message, its onMessage method is being invoked. When the EJB container removes a bean instance, it first calls the ejbRemove method before the instance is ready for garbage collection. The life cycle of a message-driven bean is depicted in the following figure.

When defining a message-driven bean in WebLogic, in most cases you will implement the onMessage method to execute a particular business task, and use the ejbCreate method to implement actions that only need to be executed once, such as looking up the home interfaces of entity beans that are invoked by the message-driven bean's onMessage method. A typical example of simple message-driven bean is given below. Notice that the ejbCreate method is used to find the home interface of a Recording entity bean, while the onMessage method processes the message and invokes the Recording bean:

/**
 * @ejbgen:message-driven
 *   ejb-name = Statistics
 *   destination-jndi-name="jms.EJBTutorialSampleJmsQ"
 *   destination-type = javax.jms.Queue
 *
 * @ejbgen:ejb-local-ref 
 * type="Entity" 
 * name="ejb/recordLink" 
 * local="bands.Recording" 
 * link="Recording" 
 * home="bands.RecordingHome"
 */
public class StatisticsBean extends GenericMessageDrivenBean implements MessageDrivenBean, MessageListener
{
  private RecordingHome recordingHome;

  public void ejbCreate() {
    try {
        javax.naming.Context ic = new InitialContext();
        recordingHome = (RecordingHome)ic.lookup("java:/comp/env/ejb/recordLink"); 
    }
    catch(NamingException ne) {
        System.out.println("Encountered the following naming exception: " + ne.getMessage());        
    }
  }
  
  public void onMessage(Message msg) {
     try {
         // read the message
         MapMessage recordingMsg = (MapMessage)msg;
         String bandName = recordingMsg.getString("bandName");
         String recordingTitle = recordingMsg.getString("recordingTitle");
         ...
         // save the rating with the recording
         Recording album = recordingHome.findByPrimaryKey(new RecordingBeanPK(bandName, recordingTitle));
         album.setRating(rating);
     }
     catch(Exception e) {
        System.out.println("Encountered the following exception: " + e.getMessage());
     }
  }
}

You can implement the ejbRemove method if cleanup is required before the object is removed, and you can implement setMessageDrivenContext method if you need access to the javax.ejb.MessageDrivenContext provided by the EJB container. The MessageDrivenContext contains information about the container, in particular its transaction methods; for more information, see your favorite J2EE documentation. A message-driven bean defined in WebLogic by default extends weblogic.ejb.GenericMessageDrivenBean, which provides empty definitions for all these methods with the exception of the onMessage method; the definition of your bean must therefore implement the onMessage method.

 


Using a JMS Control


In WebLogic you can use a JMS control to send JMS messages to a topic or queue. JMS controls can be used to send messages in page flows and web services; they cannot be used to send JMS messages in EJBs. You can use JMS controls to both send and receive messages. In this case you will only be using the JMS control to send messages, as a message-driven bean will be used to process received messages. For details on how to create JMS controls for topics and queues, see JMS Control.

The advantage of using a JMS control is that the details of the JMS messaging API are by and large taken care of by the JMS control. For example, the following code samples shows the definition of a JMS control to send messages to a queue:

/** 
 *   @jc:jms send-type="queue" send-jndi-name="jms.SamplesAppMDBQ" 
 *            connection-factory-jndi-name="weblogic.jws.jms.QueueConnectionFactory" 
 */
public interface sendToQueueControl extends JMSControl, com.bea.control.ControlExtension 
{
    /**
     * this method will send a javax.jms.Message to send-jndi-name
     */
    public void sendJMSMessage(Message msg);
    static final long serialVersionUID = 1L;
}

As the definition shows, you must still define the name of the queue to which to send the JMS message as well as the name of a QueueConnectionFactory. However, to send a message using this JMS control, you simply need to invoke the method sendJMSMessage and pass a message as the parameter. The JMS control handles the creation of a factory instance, a connection, session, and so forth.

When using a JMS control from a page flow or web service, you can use a built-in control to encapsulate all the message sending related logic, instead of defining this directly in the page flow or web service. For instance, the following built-in control code snippet uses the JMS control defined above to send 20 messages at one time to a queue.

...
public class MessageSenderImpl implements MessageSender, ControlSource
{ 
    /**
     * @common:control
     */
    private messageDriven.sendToQueueControl queueSend;

    /**
     * @common:operation
     * @common:message-buffer enable="true"
     */
    public void add20ViaQueue(int currentNum) throws JMSException
    {
        String name;
        for(int i = 0; i < 20; i++) {
           MapMessage msg = queueSend.getSession().createMapMessage();
           msg.setStringProperty("Command", "Add");
           name = Integer.toString(currentNum + i);     
           msg.setString("tokenName", name);
           queueSend.sendJMSMessage(msg);
        }
    }
}

For more information on built-in controls, see Building Custom Java Controls. The use of JMS controls and built-in controls in a page flow is demonstrated in the Message-Driven Bean Sample.


Sending Messages from EJBs


To send JMS message from an EJB, you cannot use JMS controls and must use the 'standard' JMS messaging API. (You can also use the standard messaging API in page flows and web services if you do not want to use a JMS control.) The following code sample shows a session bean sending a message to a queue. The queue and QueueConnectionFactory are defined using @ejbgen:resource-env-ref and @ejbgen:resource-ref annotations. In the bean's ejbCreate method the queue and QueueConnectionFactory are located (this only need to be done once), while the method executeTask contains the correct procedure to create a connect, session, sender, and message before sending the JMS message.

/** 

 * @ejbgen:resource-ref
 *   auth="Container"
 *   jndi-name = "weblogic.jws.jms.QueueConnectionFactory"
 *   name = "jms/QueueConnectionFactory"
 *   type="javax.jms.QueueConnectionFactory"
 * 
 * @ejbgen:resource-env-ref 
 *  jndi-name="jms.ASampleJmsQ" 
 *  name="jms/ASampleJmsQ" 
 *  type = "javax.jms.Queue" 
 *   
 * ...
 */
public class ASessionBean extends GenericSessionBean implements SessionBean
{
   private QueueConnectionFactory factory;
   private Queue queue;
    
   public void ejbCreate() {
      try {
         javax.naming.Context ic = new InitialContext();
         factory = (QueueConnectionFactory) ic.lookup("java:comp/env/jms/QueueConnectionFactory");  
         queue = (Queue) ic.lookup("java:comp/env/jms/ASampleJmsQ");
      } 
      catch (NamingException ne) {
         throw new EJBException(ne);
      }
   }

   /**
    * @ejbgen:local-method
    */
   public void executeTask(String prop1, String prop2)
   {
     try {
        //interpret the properties
        ...
        //send a message
        QueueConnection connect = factory.createQueueConnection();
        QueueSession session = connect.createQueueSession(true,Session.AUTO_ACKNOWLEDGE);
        QueueSender sender = session.createSender(queue);
        MapMessage recordingMsg = session.createMapMessage();
        recordingMsg.setString("Property1", prop1);
        recordingMsg.setString("Property2", prop2);
        sender.send(recordingMsg);
        connect.close(); 
     }
     catch(JMSException ne) {
        throw new EJBException(ne);
     }
   }
}

JMS Message Types


The JMS messaging API defines various message types, allowing for different types of information to be included in the body of a JMS message. Frequently used message types are TextMessage to send a text string, MapMessage to create sets of name-value pairs, and ObjectMessage to send a serializable object. For more details on the various message types, see your favorite J2EE documentation or the javax.jms.Message API documentation at http://java.sun.com.


Message Selectors


A JMS message can also contain message properties. There are different types of properties which can serve a number of functions. One common use of a message property is to set a message selector. A message selector is a property that is used by a message-driven bean to determine whether it should process this message or should leave its processing up to another message-driven bean listening to the same topic or queue.

The following example shows how to set a String property that will act as a message selector for a JMS MapMessage:

Message msg = session.createMapMessage();
msg.setStringProperty("MyMessage", "Build 126"");

A message-driven bean that is defined to specifically process this type of message will include a message selector property:

 * @ejbgen:message-driven 
 *   message-selector="MyMessage = 'Build126'"    
 *   ejb-name = MDBean
 * ...
 */
public class MDBean extends GenericMessageDrivenBean implements MessageDrivenBean, MessageListener
{
   ...

In other words, this bean will respond specifically to this type of message and will leave the processing of other messages up to other beans listening to this topic or queue. By using a message selector you can send different types of messages to the same channel instead of having to create a separate queue/topic for every type of message. For more details on the various message properties, see your favorite J2EE documentation or the javax.jms.Message API documentation at http://java.sun.com.

 




Processing JMS Messages


When a JMS message is sent to a topic or queue, a message-driven bean instance will interpret and process the message, as specified in its onMessage method. When a JMS message is sent to a topic, a publish-and-subscribe system, an instance of every message-driven bean class listening to this topic will in principle receive and process this message. However, if the message contains a message selector, only the message-driven bean(s) matching the message selector will process the message. When a JMS message is sent to a queue, a point-to-point system, only one message-driven bean will process the message, even when multiple bean classes are listening to the queue. Again, the use of a message selector might limit the bean processing the message. For more on message selectors, .

How the JMS message is processed fully depends on the business task that is being modeled. It might range from simply logging the message to executing a range of different tasks which include invoking methods on session and entity beans, or sending JMS messages to be processed by other message-driven beans. The following code sample shows one use of a message-driven bean. This bean responds only to JMS messages delivered via the jms/SamplesAppMDBQ queue and contain the message selector Command= 'Delete'. When processing a JMS message, an instance of this bean invokes the query method findAll of the entity bean SimpleToken, and subsequently deletes all SimpleToken records from the underlying database.

/**

 * @ejbgen:message-driven 
 *   message-selector="Command = 'Delete'" 
 *   ejb-name = DeleteViaQMD
 *   destination-jndi-name = jms/SamplesAppMDBQ
 *   destination-type = javax.jms.Queue
 *
 *  @ejbgen:ejb-local-ref link="SimpleToken"
 */
public class DeleteViaQMDBean
  extends GenericMessageDrivenBean
  implements MessageDrivenBean, MessageListener
{
  private SimpleTokenHome tokenHome;
  
  public void ejbCreate() {
     try {
        javax.naming.Context ic = new InitialContext();
        tokenHome = (SimpleTokenHome)ic.lookup("java:/comp/env/ejb/SimpleToken"); 
     }
     catch(NamingException ne) {
        System.out.println("Encountered the following naming exception: " + ne.getMessage());        
     }
  }

  public void onMessage(Message msg) {
     try {
        Iterator allIter = tokenHome.findAll().iterator();
        while(allIter.hasNext()) {
            ((SimpleToken) allIter.next()).remove();
        }
     }
     catch(Exception e) {
        System.out.println("Encountered the following exception: " + e.getMessage());
     }
  }
} 

Acknowledgement and Transactions


When a message-driven bean instance receives a message, and it is not part of a container-managed transaction, by default it immediately sends an acknowledgement to the JMS provider notifying that the message has been received. This will prevent the JMS provider from attempting to redeliver it. However, the acknowledgement only indicates that a message has been successfully received, but it does not guarantee that the message is successfully processed. For instance, a system exception might occur when attempting to locate an entity bean or update its records, causing the processing to fail.

If you want to ensure that a message is redelivered when processing fails, you can make the message-driven bean be part of a transaction. The easiest approach is to use container-managed transaction, where the EJB container is responsible for transaction management. To enable container-managed transaction for a message-driven bean, make sure that your cursor is placed inside the ejbgen:message-driven tag and use the Property Editor to set the transaction-type to Container and the default-transaction to Required. When JMS message processing executes successfully, any changes made during this business task, such as update to entity bean records, are committed and acknowledgement is sent to the JMS provider. However, when JMS message processing fails due to a system exception, any changes are rolled back and receipt is not acknowledged. In other words, after processing fails, the JMS provider will attempt to resend the JMS message until processing is successfully or until the maximum number of redelivery attempts specified for this topic or queue has been reached.

Note. When a message-driven bean is part of a transaction, it executes as part of its own transaction. In other words, if the transaction fails, changes that were made as part of the onMessage method are rolled back, but the occurrence of an exception has no direct effect on the EJB or client application sending the JMS message, as the sender and the message-driven bean are decoupled.

To learn more about container-managed transactions, see EJBs and Transactions. To learn more about bean-managed transaction (that is, explicit transaction management), please refer to your favorite J2EE documentation.



Be the first one to comment on this page.




  Weblogic Tutorial eBooks

No eBooks on Weblogic could be found as of now.

 
 Weblogic Tutorial FAQs
More Links » »
 
 Weblogic Tutorial Interview Questions
More Links » »
 
 Weblogic Tutorial Articles

No Weblogic Articles could be found as of now.

 
 Weblogic Tutorial News

No News on Weblogic could be found as of now.

 
 Weblogic Tutorial Jobs

No Weblogic Articles could be found as of now.


Share And Enjoy:These icons link to social bookmarking sites where readers can share and discover new web pages.
  • blinkbits
  • BlinkList
  • blogmarks
  • co.mments
  • connotea
  • del.icio.us
  • De.lirio.us
  • digg
  • Fark
  • feedmelinks
  • Furl
  • LinkaGoGo
  • Ma.gnolia
  • NewsVine
  • Netvouz
  • RawSugar
  • Reddit
  • scuttle
  • Shadows
  • Simpy
  • Smarking
  • Spurl
  • TailRank
  • Wists
  • YahooMyWeb

Previoushome Next

Keywords: Developing Message-Driven Beans, WEBLOGIC, WebLogic, WebLogic tutorials, WebLogic tutorial pdf, history of WebLogic, How To Deploy An Application Using WebLogic , learn WebLogic

HTML Quizzes
HTML Quiz
XHTML Quiz
CSS Quiz
TCP/IP Quiz
CSS 1.0 Quiz
CSS 2.0 Quiz
HLML Quiz
XML Quizzes
XML Quiz
XSL Quiz
XSLT Quiz
DTD Quiz
Schema Quiz
XForms Quiz
XSL-FO Quiz
XML DOM Quiz
XLink Quiz
XQuery Quiz
XPath Quiz
XPointer Quiz
RDF Quiz
SOAP Quiz
WSDL Quiz
RSS Quiz
WAP Quiz
Web Services Quiz
Browser Scripting Quizzes
JavaScript Quiz
VBScript Quiz
DHTML Quiz
HTML DOM Quiz
WMLScript Quiz
E4X Quiz
Server Scripting Quizzes
ASP Quiz
PERL Quiz
SQL Quiz
ADO Quiz
CVS Quiz
Python Quiz
Apple Script Quiz
PL/SQL Quiz
SQL Server Quiz
PHP Quiz
.NET (dotnet) Quizzes
Microsoft.Net Quiz
ASP.Net Quiz
.Net Mobile Quiz
C# : C Sharp Quiz
ADO.NET Quiz
VB.NET Quiz
VC++ Quiz
Multimedia Quizzes
SVG Quiz
Flash Quiz
Media Quiz
SMIL Quiz
Photoshop Quiz
Gimp Quiz
Matlab Quiz
Gnuplot Programming Quiz
GIF Animation Quiz
Scientific Visualization Quiz
Graphics Quiz
Web Building Quizzes
Web Browsers Quiz
Web Hosting Quiz
W3C Quiz
Web Building Quiz
Web Quality Quiz
Web Semantic Quiz
Web Careers Quiz
Weblogic Quiz
SEO Quiz
Web Site Hosting Quiz
Domain Name Quiz
Java Quizzes
Java Quiz
JSP Quiz
Servlets Quiz
Struts Quiz
EJB Quiz
JMS Quiz
JMX Quiz
Eclipse Quiz
J2ME Quiz
JBOSS Quiz
Programming Langauges Quizzes
C Quiz
C++ Quiz
Visual Basic Quiz
Data Structures Using C Quiz
Cobol Quiz
Assembly Language Quiz
Mainframe Quiz
Forth Programming Quiz
Lisp Programming Quiz
Pascal Quiz
Delphi Quiz
Fortran Quiz
OOPs Quiz
Data Warehousing Quiz
CGI Programming Quiz
Emacs Quiz
Gnome Quiz
ILU Quiz
Soft Skills Quizzes
Communication Skills Quiz
Time Management Quiz
Project Management Quiz
Team Work Quiz
Leadership Skills Quiz
Corporate Communication Quiz
Negotiation Skills Quiz
Database Quizzes
Oracle Quiz
MySQL Quiz
Operating System Quizzes
BSD Quiz
Symbian Quiz
Unix Quiz
Internet Quiz
IP-Masquerading Quiz
IPC Quiz
MIDI Quiz
Software Testing Quizzes
Testing Quiz
Firewalls Quiz
SAP Module Quizzes
ERP Quiz
ABAP Quiz
Business Warehousing Quiz
SAP Basis Quiz
Material Management Quiz
Sales & Distribution Quiz
Human Resource Quiz
Netweaver Quiz
Customer Relationship Management Quiz
Production and Planning Quiz
Networking Programming Quizzes
Corba Quiz
Networking Quiz
Microsoft Office Quizzes
Microsoft Word Quiz
Microsoft Outlook Quiz
Microsoft PowerPoint Quiz
Microsoft Publisher Quiz
Microsoft Excel Quiz
Microsoft Front Page Quiz
Microsoft InfoPath Quiz
Microsoft Access Quiz
Accounting Quizzes
Financial Accounting Quiz
Managerial Accounting Quiz
Testimonials | Contact Us | Link to Us | Site Map
Copyright ? 2008. Academic Tutorials.com. All rights reserved Privacy Policies | About Us
Our Portals : Academic Tutorials | Best eBooksworld | Beyond Stats | City Details | Interview Questions | Discussions World | Excellent Mobiles | Free Bangalore | Give Me The Code | Gog Logo | Indian Free Ads | Jobs Assist | New Interview Questions | One Stop FAQs | One Stop GATE | One Stop GRE | One Stop IAS | One Stop MBA | One Stop SAP | One Stop Testing | Webhosting in India | Dedicated Server in India | Sirf Dosti | Source Codes World | Tasty Food | Tech Archive | Testing Interview Questions | Tests World | The Galz | Top Masala | Vyom | Vyom eBooks | Vyom International | Vyom Links | Vyoms | Vyom World | Important Websites
Copyright ? 2003-2024 Vyom Technosoft Pvt. Ltd., All Rights Reserved.