MrBool
You must be logged in to give feedback. Click here to login
[Close]

You must be logged to download.

Click here to login

[Close]

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

[Close]

MrBool is totally free and you can help us to help the Developers Community around the world

Yes, I'd like to help the MrBool and the Developers Community before download

No, I'd like to download without make the donation

Seam integration on Java EE

This article will discuss about seam framework and its integration on Java EE.

[close]

You didn't like the quality of this content?

Would you like to comment what you didn't like?

Introduction:

Seam is a strong component based framework. Seam integrates technologies like JavaScript, JSP, JSTL, Ajax, JPA and JBPM as well. Seam is an application development framework for Java EE that connected the component and other models of JSF and EJB 3.0, which is a strong component dependent framework, providing a streamlined programming model for web-based java and Java EE enterprise applications. Therefore, Seam works with JBoss and Java EE. BY using Seam framework, we can bind our EJB components directly to JSF pages, so we do not need to go through any kind of XML configuration for that.

Creating entity by SEAM

Here we mention the easier way of integration of seam with Java EE. The Seam framework extends and offers the facilities of the annotations defined by EJB 3.0 with a new and latest set of annotations for declarative state management, for this reason we are able to use it quite easily that state validation and declarative context demarcation, eliminating much of the XML required by plain JSF. If we use seam framework, we will find an easy way to create all the entities by some clicks. When we generate the entity by SEAM-generate entity, then we will find many facilities on it. The annotation provides the facilities of preventing the entrance null value by @NotNull, @email etc. If the seam finds any One to Many relation, Many to One within the table structure than it create "@ManyToOne" or @OneToMany(mapped By="divisionId"). The primary key of the entity creates this. Therefore, by this way we can create all the entities, existing in the database.

Listing 1: Creating Entity by Seam

@Entity
@Name("configDivision")
@Scope(ScopeType.SESSION)
@Table(name="pms.config_division")
Class Name: CongigDivision.java


package org.domain.pms.entities;
import java.io.Serializable;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.hibernate.validator.Length;
import org.hibernate.validator.NotEmpty;
import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
@Entity
@Name("configDivision")
@Scope(ScopeType.SESSION)
@Table(name="pms.config_division")
public class ConfigDivision implements Serializable {
	@Id@GeneratedValue
	@Column(name="DIVISION_ID")
	private long divisionId;	
	@Column(name="DIVISION_NAME")	
	private String divisionName;
	@Column(name="DIVISION_NAME_BEN")
	private String divisionNameBen;
	@Column(name="ACTIVATION_STATUS")
	private String activationStatus;
       @OneToMany(mappedBy="divisionId")
	private Set<ConfigHoliday> configHolidayCollection;
       @OneToMany(mappedBy="divisionId")
	private Set<StaffProfile> staffProfileCollection;

	@OneToMany(mappedBy="joining")
	private Set<StaffProfile> staffProfileCollection2;

	@OneToMany(mappedBy="divisionId")
	private Set<ConfigWing> configWingCollection;

	@OneToMany(mappedBy="divisionId")
	private Set<ConfigRank> configRankCollection;
	@OneToMany(mappedBy="divisionId")
	private Set<ConfigLeaveType> configLeaveTypeCollection;
       @OneToMany(mappedBy="divisionId")
	private Set<ConfigKeyword> configKeywordCollection;
       @OneToMany(mappedBy="divisionId")
	private Set<ConfigKeyword> configPayGradeCollection;
       private static final long serialVersionUID = 1L;
       public ConfigDivision() {
		super();
	}
	public long getDivisionId() {
		return this.divisionId;
	}
	public void setDivisionId(long divisionId) {
		this.divisionId = divisionId;
	}
	public String getDivisionName() {
		return this.divisionName;
	}
	public void setDivisionName(String divisionName) {
		this.divisionName = divisionName;
	}
	public String getDivisionNameBen() {
		return this.divisionNameBen;
	}
	public void setDivisionNameBen(String divisionNameBen) {
		this.divisionNameBen = divisionNameBen;
	}
	public String getActivationStatus() {
		return this.activationStatus;
	}
	public void setActivationStatus(String activationStatus) {
		this.activationStatus = activationStatus;
	}
	public Set<ConfigHoliday> getConfigHolidayCollection() {
		return this.configHolidayCollection;
	}
	public void setConfigHolidayCollection(Set<ConfigHoliday> configHolidayCollection) {
		this.configHolidayCollection = configHolidayCollection;
	}
	public Set<StaffProfile> getStaffProfileCollection() {
		return this.staffProfileCollection;
	}
	public void setStaffProfileCollection(Set<StaffProfile> staffProfileCollection) {
		this.staffProfileCollection = staffProfileCollection;
	}
	public Set<StaffProfile> getStaffProfileCollection2() {
		return this.staffProfileCollection2;
	}
	public void setStaffProfileCollection2(Set<StaffProfile> staffProfileCollection2) {
		this.staffProfileCollection2 = staffProfileCollection2;
	}
	public Set<ConfigWing> getConfigWingCollection() {
		return this.configWingCollection;
	}
	public void setConfigWingCollection(Set<ConfigWing> configWingCollection) {
		this.configWingCollection = configWingCollection;
	}
	public Set<ConfigRank> getConfigRankCollection() {
		return this.configRankCollection;
	}
	public void setConfigRankCollection(Set<ConfigRank> configRankCollection) {
		this.configRankCollection = configRankCollection;
	}
	public Set<ConfigLeaveType> getConfigLeaveTypeCollection() {
		return this.configLeaveTypeCollection;
	}
	public void setConfigLeaveTypeCollection(Set<ConfigLeaveType> configLeaveTypeCollection) {
		this.configLeaveTypeCollection = configLeaveTypeCollection;
	}
	public Set<ConfigKeyword> getConfigKeywordCollection() {
		return this.configKeywordCollection;
	}
	public void setConfigKeywordCollection(Set<ConfigKeyword> configKeywordCollection) {
		this.configKeywordCollection = configKeywordCollection;
	}

	public Set<ConfigKeyword> getConfigPayGradeCollection() {
		return configPayGradeCollection;
	}
public void setConfigPayGradeCollection(
			Set<ConfigKeyword> configPayGradeCollection) {
		this.configPayGradeCollection = configPayGradeCollection;
	}

Here we follow the MVC pattern to make or build any application. The entities act like the model of the pattern. Now we discuss the controller of seam framework. We can use JPA (Java persistence API) to make the entities. SEAM is a very well define and very user-friendly framework. Therefore, we can build our application and enterprise application by the help of SEAM.

Controller or Action Class

In seam framework, the programming model is declarative. Seam introduces modest and declarative application state management for 'POJO' components. Seam components are statefull, stateless and contextual; with a well prove define context management. However, we can define what will be the state of action class. The performance problem occurs when all the classes define statefull. However, this time memory requires killing the useless objects. Seam components may take advantage of SVN or VSS that is subversion of control, a generalization of dependency injection and some other way, which applies, to statefull components as well as stateless services. In seam framework, the Action class controls all the work and makes association, which is needed. When any action occurs, the action class determined which performance needs to take place.

Listing 2: ConfigDivisionAction.java

package org.domain.pms.session;
import static org.jboss.seam.ScopeType.SESSION;
import static javax.persistence.PersistenceContextType.EXTENDED;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.ejb.Remove;
import javax.ejb.Stateful;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;
import org.domain.pms.entities.AuditTrail;
import org.domain.pms.entities.ConfigDivision;
import org.domain.pms.entities.LoginInfo;
import org.domain.pms.entities.StaffProfile;
import org.domain.pms.util.ConstantValues;
import org.domain.pms.util.DbTable;
import org.jboss.seam.annotations.Destroy;
import org.jboss.seam.annotations.Factory;
import org.jboss.seam.annotations.In;
import org.jboss.seam.annotations.Logger;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Out;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.datamodel.DataModel;
import org.jboss.seam.annotations.datamodel.DataModelSelection;
import org.jboss.seam.log.Log;
import org.jboss.seam.security.Credentials;
import org.jboss.seam.security.Identity;
@Stateful
@Name("configDivisionAction")
@Scope(SESSION)
public class ConfigDivisionAction implements ConfigDivisionActionLocal {

	@In(required=false)
	private EntityManager entityManager;
	@Logger
	private static Log log;
       private Set<Integer> keys = new HashSet<Integer>();
       public void setKeys(Set<Integer> keys) {
		this.keys = keys;
	}
	public Set<Integer> getKeys() {
		return keys;
	}

	@DataModel
	List<ConfigDivision> configDivisionList;
	@DataModelSelection("configDivisionList")
	@In(required=false) @Out(required=false)
	private ConfigDivision configDivision;
	
	@DataModel
	List<ConfigDivision> inactiveDivList;
	@DataModelSelection("inactiveDivList")
	@In(required=false) @Out(required=false)
	private ConfigDivision inactiveDiv;
	
	@DataModel
	List<AuditTrail> divTrailList;
	private AuditTrailAction auditTrailAction;
	private AuditTrail auditTrail;
	
	@In Credentials credentials;
	@In Identity identity;
	//	list all existing Divisions
	@Factory("configDivisionList")
	public void viewAll() {
		
		long divId = LoggedUserInfo.instance().getDivisionId();
		
		Query q = entityManager.createQuery("select div from ConfigDivision div where div.divisionId>2 and div.activationStatus='Active'");			
		configDivisionList = (List<ConfigDivision>) q.getResultList();
		
		//configDivisionList = (List<ConfigDivision>)em.createQuery("select div from ConfigDivision div").getResultList();
		//log.info("the list size is"+ configDivisionList.size());

	}

//	list all inactive Wings
	@Factory("inactiveDivList")
	public void viewAllInactives() {
		
		try {
			Query q = entityManager.createQuery("select div from ConfigDivision div where div.divisionId>2 and div.activationStatus=?1 order by div.divisionId");
			q.setParameter(1, "Inactive");
			
			inactiveDivList = (List<ConfigDivision>) q.getResultList();
			
		} catch (Exception e) {
			//log.info("==== == == error at inactiveWingList generation == ");
		}			
	}
	//	go for Division details 
	public String details() {		
		
		try{
			Query q = entityManager.createQuery("select at from AuditTrail at where documentId=?1 order by at.actionId desc");
			q.setParameter(1, configDivision.getDivisionId());		
			divTrailList = q.getResultList();
			
		}catch(Exception e){
			//log.info("--->>> Error generating audit trail list"+e);
		}
		
		return null;
	}

//	go for Division details 
	public String inactDetails() {		
		this.configDivision = this.inactiveDiv;
		try{
			Query q = entityManager.createQuery("select at from AuditTrail at where documentId=?1 order by at.actionId desc");
			q.setParameter(1, configDivision.getDivisionId());		
			divTrailList = q.getResultList();
			
		}catch(Exception e){
			//log.info("--->>> Error generating audit trail list"+e);
		}
		
		return null;
	}
	
	//	delete a Division
	public String delete() {
		try{
			//log.info("delete division -- >> "+configDivision.getDivisionName());
						entityManager.remove(entityManager.merge(configDivision));
			configDivisionList.remove(configDivision);
		}catch(Exception e){
			//log.info("Error at delete method of configDivisionAction "+e);
			e.printStackTrace();
		}				

		// return "/config/configDivisionList.xhtml";
		return null;
	}

	// 	add a new Division
	public String submit() {
		try{
			String auditAction="";
			
			if(configDivision.getDivisionId() > 0)
			{
				entityManager.merge(configDivision);
				if(configDivision.getActivationStatus().equalsIgnoreCase("inactive"))
					auditAction = ConstantValues.UPDATED_AS_INACTIVE;
				else
					auditAction = ConstantValues.UPDATED;
			}else{
				entityManager.persist(configDivision);
				if(configDivision.getActivationStatus().equalsIgnoreCase("inactive"))
					auditAction = ConstantValues.CREATED_AS_INACTIVE;
				else
					auditAction = ConstantValues.CREATED;
			}

			viewAll();
			
			viewAllInactives();
		
			//---------------------audit trail
				keepTrail(auditAction, configDivision);

		}catch(Exception e){
			//log.info("Error at Submit method of configDivisionAction "+e);
		}

		return null;
	}

	    public String create() {
		configDivision = new ConfigDivision();
		configDivision.setActivationStatus("Active");	

		return null;
		//return "/config/configDivisionForm.xhtml";
	}


	//cancel adding form
	public String cancel() {		
		return "/config/configDivisionList.xhtml";
	}
	// this method adds trail to audit
	private void keepTrail(String auditAction, ConfigDivision cdiv){
		try{
			auditTrail= new AuditTrail();
			auditTrailAction = new AuditTrailAction();
			
			/*String query = "select u from LoginInfo u where upper(u.loginName)='"+credentials.getUsername().toUpperCase()+"'";
			LoginInfo user =  (LoginInfo) entityManager.createQuery(query).getSingleResult();
			StaffProfile sf = user.getStaffId();
			
			String fullName = sf.getFirstName()+" "+sf.getMiddleName()+" "+sf.getSurname();*/
			
			StaffProfile sf = LoggedUserInfo.instance().getLoggedUser();
			//auditTrail = auditTrailAction.append( fullName +" [ "+ sf.getRankId().getRankTitle() + " ] ", auditAction , cdiv.getDivisionId());
			
			auditTrail = auditTrailAction.append( sf, auditAction , cdiv.getDivisionId(), DbTable.CONFIG_DIVISION);
			
			entityManager.persist(auditTrail);			
			auditTrail = null;
			auditTrailAction = null;
			
		}catch(Exception e){
			//log.info("Error in Audit trail............"+e);			
		}		

	}
       @Destroy @Remove
	public void destroy()
	{    	
	}
}

To retrieve the whole data from the data table the seam framework uses @Factory. The @DataModel uses to select the data, when any one clicks and pickup data from any list. By the way of using interface, we connect with the presentation layer to Action layer. If the interface stores in the same machine, we use @Local annotation on it. If we use remotely, we need to use ‘@Remote’ annotation on the interface.

Listing 3: Interface

package org.domain.pms.session;
import javax.ejb.Local;

@Local
public interface ConfigDivisionActionLocal {
	public void viewAll();
	public void viewAllInactives();
	public String details();
	public String inactDetails();
	public String delete();
	public String submit();
	public String create();
	public String cancel();
	public void destroy();
}

Now we will go through the presentation layer of MVC pattern. For preview the output we use XHTML. XHTML is very light weight and case sensitive. By the action class name and the method name, we can build a connection between action and presentation layer in seam framework.

Here we preview the pages of configDivision.

Listing 4: configDivision.xhtml

<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" 
      xmlns:ui="http://java.sun.com/jsf/facelets" 
      xmlns:s="http://jboss.com/products/seam/taglib"
      xmlns:h="http://java.sun.com/jsf/html" 
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:a4j="http://richfaces.org/a4j"
      xmlns:rich="http://richfaces.org/rich">

<ui:composition template="/templates/main.xhtml">

<ui:define name="body">

    <h:form id="frmName">

        <rich:panel>
            <f:facet name="header"><h:outputText value="#{messages.division} #{messages.list}" styleClass="#{localeSelector.language}textTopMenu"/></f:facet>
           
           
            <rich:spacer height="15" />
            
            
                <rich:dataTable id="configDivisionList" value="#{configDivisionList}" var="confDiv" width="100%" rows="10" columnClasses="td10,td30,td30,td30">
                	
                	<rich:column sortBy="#{confDiv.divisionName}" rendered="#{localeSelector.language.equalsIgnoreCase('en')}"> 
                		<f:facet name="header">
                			<h:outputText value="#{messages.division}" styleClass="#{localeSelector.language}FormLabel"/>
                		</f:facet>
                	    <h:outputText value="#{confDiv.divisionName}" styleClass="#{localeSelector.language}FormLabel"/>
                	</rich:column>
                	
                	<rich:column sortBy="#{confDiv.divisionNameBen}" rendered="#{localeSelector.language.equalsIgnoreCase('bg')}" >
                		<f:facet name="header">
                			<h:outputText value="#{messages.division}" styleClass="#{localeSelector.language}FormLabel"/>
                		</f:facet>
                	    <h:outputText value="#{confDiv.divisionNameBen}" styleClass="#{localeSelector.language}FormLabel"/>
                	</rich:column>
                	<rich:column >
                		<f:facet name="header">
                			<h:outputText value="#{messages.action}" styleClass="#{localeSelector.language}FormLabel"/>
                		</f:facet>
                		<s:link value="#{messages.edit}" action="#{configDivisionAction.details}" styleClass="#{localeSelector.language}FormLabel"/>
                		<rich:spacer width="5" />
                		<s:link value="#{messages.delete}" action="#{configDivisionAction.delete}" styleClass="#{localeSelector.language}FormLabel"/> 
                	</rich:column>
                	        
                	<f:facet name="footer">
    					<rich:datascroller id="dscroller" renderIfSinglePage="false"></rich:datascroller>
 					</f:facet>   
 					 					       			 	    	
                </rich:dataTable>
              <rich:modalPanel  id="mp" autosized="true" zindex="2000">
            <f:facet name="header">
                <h:outputText value="Modal Panel Title" />
            </f:facet>
            <f:facet name="controls">
            </f:facet>
                 <h:panelGrid columns="4" >                  
                   	                 
	                   <h:outputLabel for="divisionName" value="#{messages.divisionEN}" styleClass="#{localeSelector.language=='en' ? 'entext' : 'bgtext' }" />
	                   <h:outputText value=":" />	                 
	                  	<h:inputText id="divisionName" value="#{configDivision.divisionName}" styleClass="enFormLabel"/>
	                    <rich:message for="divisionName" />	                
	                    
	                    <h:outputLabel for="divisionNameBG" value="#{messages.divisionBG}" styleClass="#{localeSelector.language}text" />
	                    <h:outputText value=":" />	                 
	                  	<h:inputText id="divisionNameBG" value="#{configDivision.divisionNameBen}" styleClass="bgFormLabel"/>
	                    <rich:message for="divisionNameBG" />
	                    <script>makePhoneticEditor('configDivisionForm:divisionNameBG');</script>
	                    	                                       	
                </h:panelGrid>
                <div class="actionButtons">
            	<a4j:commandButton value="#{messages.submit}"  onmouseover="OnMouseOverColor(this)" onmouseout="OnMouseOutColor(this)"  styleClass="#{localeSelector.language}FormLabel"/>
            	<a4j:commandButton id="cancelButton" value="#{messages.cancel}"  onmouseover="OnMouseOverColor(this)" onmouseout="OnMouseOutColor(this)" styleClass="#{localeSelector.language}FormLabel">
            	<rich:componentControl for="mp" attachTo="cancelButton" operation="hide" event="onclick"/> 
            	</a4j:commandButton>
        		</div>
                
        </rich:modalPanel>
        <h:outputLink value="#" id="link">
        	<h:outputText value="#{messages.new} #{messages.division}" styleClass="#{localeSelector.language}FormLabel"/> 
        	<rich:componentControl for="mp" attachTo="link" operation="show" event="onclick"/>
    	</h:outputLink>
               <rich:jQuery selector="#configDivisionList tr:odd" query="addClass('odd-row')" />
                 <rich:jQuery selector="#configDivisionList tr:even" query="addClass('even-row')" />
                    <rich:jQuery selector="#configDivisionList tr" 
                  query="mouseover(function(){jQuery(this).addClass('active-row')})"/>
                  <rich:jQuery selector="#configDivisionList tr" 
                    query="mouseout(function(){jQuery(this).removeClass('active-row')})"/>
           
        </rich:panel>

    </h:form>
    </ui:define>
</ui:composition>
 
</html>

In this application, the ‘configDivision’ page is the landing page of these tutorials. To call any method from XHTML page we need “configDivisionAction’. Submit” to call the submit method. We need to configure some other configuration. That is the deployment descriptor and component .xml. If we need to use any language, we can use message.properties to get the facilities.

At last we preview the deployment descriptor to include the SEAM framework.

Listing 5: web.xml


<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
  <display-name>pms-web</display-name>
  <welcome-file-list>
    <welcome-file>index.html</welcome-file>
    <welcome-file>index.htm</welcome-file>
    <welcome-file>index.jsp</welcome-file>
    <welcome-file>default.html</welcome-file>
    <welcome-file>default.htm</welcome-file>
    <welcome-file>default.jsp</welcome-file>
  </welcome-file-list>
  <servlet>
    <servlet-name>Faces Servlet</servlet-name>
    <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>Faces Servlet</servlet-name>
    <url-pattern>*.seam</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>org.richfaces.SKIN</param-name>
    <param-value>deepMarine</param-value>
  </context-param>
  <listener>
    <listener-class>org.jboss.seam.servlet.SeamListener</listener-class>
  </listener>
  <filter>
    <filter-name>Seam Filter</filter-name>
    <filter-class>org.jboss.seam.servlet.SeamFilter</filter-class>
    <init-param>
      <param-name>createTempFiles</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>maxRequestSize</param-name>
      <param-value>10000000</param-value>
    </init-param>
  </filter>
  <filter-mapping>
    <filter-name>Seam Filter</filter-name>
    <url-pattern>/*</url-pattern>
  </filter-mapping>
  <servlet>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <servlet-class>org.jboss.seam.servlet.SeamResourceServlet</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>Seam Resource Servlet</servlet-name>
    <url-pattern>/seam/resource/*</url-pattern>
  </servlet-mapping>
  <context-param>
    <param-name>facelets.DEVELOPMENT</param-name>
    <param-value>true</param-value>
  </context-param>
  <context-param>
    <param-name>javax.faces.DEFAULT_SUFFIX</param-name>
    <param-value>.xhtml</param-value>
  </context-param>
  <security-constraint>
    <display-name>Restrict raw XHTML Documents</display-name>
    <web-resource-collection>
      <web-resource-name>XHTML</web-resource-name>
      <url-pattern>*.xhtml</url-pattern>
    </web-resource-collection>
    <auth-constraint/>
  </security-constraint>
   
   
     
   <session-config>
  	<session-timeout>480</session-timeout>
 </session-config>
</web-app>

If we want to run the page then we need to configure it within Jboss or any other web server. The running url will be http://localhost:8080/portal-web/congigDivision.seam.

At last, Seam is a powerful open source development platform for building rich Internet applications in Java and Java EE framework.

This is all for today’s article. See you next time.



My main area of specialization is Java and J2EE. I have worked on many international projects like Recorders,Websites,Crawlers etc.Also i am an Oracle Certified java professional as well as DB2 certified

What did you think of this post?

Did you like the post?

Help us to keep publishing good contents like this.

SUPPORT US

funded

remaining

[Close]
To have full access to this post (or download the associated files) you must have MrBool Credits.

  See the prices for this post in Mr.Bool Credits System below:

Individually � in this case the price for this post is US$ 0,00 (Buy it now)
in this case you will buy only this video by paying the full price with no discount.

Package of 10 credits - in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download few videos. In this plan you will receive a discount of 50% in each video. Subscribe for this package!

Package of 50 credits � in this case the price for this post is US$ 0,00
This subscription is ideal if you want to download several videos. In this plan you will receive a discount of 83% in each video. Subscribe for this package!


> More info about MrBool Credits
[Close]
You must be logged to download.

Click here to login