How to Create a New JSF Project

Developing Java EE applications is faster and far less demanding when you can use NetBeans. The guide quickly familiarizes you with this popular Integrated Development Environment (IDE) through practical instruction.


Java EE 6 Development with NetBeans 7

Java EE 6 Development with NetBeans 7

Develop professional enterprise Java EE applications quickly and easily with this popular IDE

        Read more about this book      

(For more resources on Java, see here.)

Introduction to JavaServer faces

Before JSF existed, most Java web applications were typically developed using non-standard web application frameworks such as Apache Struts, Tapestry, Spring Web MVC, or many others. These frameworks are built on top of the Servlet and JSP standards, and automate a lot of functionality that needs to be manually coded when using these APIs directly.

Having a wide variety of web application frameworks available, often resulted in "analysis paralysis", that is, developers often spend an inordinate amount of time evaluating frameworks for their applications.

The introduction of JSF to the Java EE specification resulted in having a standard web application framework available in any Java EE compliant application server.

We don't mean to imply that other web application frameworks are obsolete or that they shouldn't be used at all. However, a lot of organizations consider JSF the "safe" choice since it is part of the standard and should be well supported for the foreseeable future. Additionally, NetBeans offers excellent JSF support, making JSF a very attractive choice.

Strictly speaking, JSF is not a web application framework per se, but a component framework. In theory, JSF can be used to write applications that are not web-based, however, in practice JSF is almost always used for this purpose.

In addition to being the standard Java EE component framework, one benefit of JSF is that it provides good support for tools vendors, allowing tools such as NetBeans to take advantage of the JSF component model with drag and drop support for components.


Developing our first JSF application

From an application developer's point of view, a JSF application consists of a series of XHTML pages containing custom JSF tags, one or more JSF managed beans, and an optional configuration file named faces-config.xml.

faces-config.xml used to be required in JSF 1.x, however, in JSF 2.0, some conventions were introduced that reduce the need for configuration. Additonally, a lot of JSF configuration can be specified using annotations, reducing, and in some cases, eliminating the need for this XML configuration file.

Creating a new JSF project

To create a new JSF project, we need to go to File | New Project, select the Java Web project category, and Web Application as the project type.

After clicking Next>, we need to enter a project name, and optionally change other information for our project, although NetBeans provides sensible defaults.

Java EE 6 Development with NetBeans 7

On the next page in the wizard, we can select the server, Java EE version, and context path of our application. In our example we will simply pick the default values.

Java EE 6 Development with NetBeans 7

On the next page of the new project wizard, we can select what frameworks our web application will use.

Java EE 6 Development with NetBeans 7

Unsurprisingly, for JSF applications we need to select the JavaServer Faces framework.

When clicking on Finish, the wizard generates a skeleton JSF project for us, consisting of a single facelet file called index.xhtml, a web.xml configuration file.

Java EE 6 Development with NetBeans 7

web.xml is the standard, optional configuration file needed for Java web applications, this file became optional in version 3.0 of the Servlet API, which was introduced with Java EE 6. In many cases, web.xml is not needed anymore, since most of the configuration options can now be specified via annotations. For JSF applications, however, it is a good idea to add one, since it allows us to specify the JSF project stage.

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns=""
<servlet-name>Faces Servlet</servlet-name>
<servlet-name>Faces Servlet</servlet-name>

As we can see, NetBeans automatically sets the JSF project stage to Development, setting the project stage to development configures JSF to provide additional debugging help not present in other stages. For example, one common problem when developing a page is that while a page is being developed, validation for one or more of the fields on the page fails, but the developer has not added an <h:message> or <h:messages> tag to the page. When this happens and the form is submitted, the page seems to do nothing, or page navigation doesn't seem to be working. When setting the project stage to Development, these validation errors will automatically be added to the page, without the developer having to explicitly add one of these tags to the page (we should, of course, add the tags before releasing our code to production, since our users will not see the automatically generated validation errors).

The following are the valid values for the javax.faces.PROJECT_STAGE context parameter for the faces servlet:

  • Development
  • Production
  • SystemTest
  • UnitTest

The Development project stage adds additional debugging information to ease development. The Production project stage focuses on performance. The other two valid values for the project stage (SystemTest and UnitTest), allow us to implement our own custom behavior for these two phases. The javax.faces.application.Application class has a getProjectStage() method that allows us to obtain the current project stage. Based on the value of this method, we can implement the code that will only be executed in the appropriate stage. The following code snippet illustrates this:

public void someMethod() {
FacesContext facesContext = FacesContext.getCurrentInstance();
Application application = facesContext.getApplication();
ProjectStage projectStage = application.getProjectStage();
if (projectStage.equals(ProjectStage.Development)) {
//do development stuff
} else if (projectStage.equals(ProjectStage.Production)) {
//do production stuff
} else if (projectStage.equals(ProjectStage.SystemTest)) {
// do system test stuff
} else if (projectStage.equals(ProjectStage.UnitTest)) {
//do unit test stuff

As illustrated in the snippet above, we can implement the code to be executed in any valid project stage, based on the return value of the getProjectStage() method of the Application class.

When creating a Java Web project using JSF, a facelet is automatically generated.

The generated facelet file looks like this:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns=""
<title>Facelet Title</title>
Hello from Facelets

As we can see, a facelet is nothing but an XHTML file using some facelets-specific XML name spaces. In the automatically generated page above, the following namespace definition allows us to use the "h" (for HTML) JSF component library:


The above namespace declaration allows us to use JSF specific tags such as <h:head> and <h:body> which are a drop in replacement for the standard HTML/XHTML <head> and <body> tags, respectively.

The application generated by the new project wizard is a simple, but complete JSF web application. We can see it in action by right-clicking on our project in the project window and selecting Run. At this point the application server is started (if it wasn't already running), the application is deployed and the default system browser opens, displaying our application's default page.

Java EE 6 Development with NetBeans 7

Modifying our page to capture user data

The generated application, of course, is nothing but a starting point for us to create a new application. We will now modify the generated index.xhtml file to collect some data from the user.

The first thing we need to do is add an <h:form> tag to our page. The <h:form> tag is equivalent to the <form> tag in standard HTML pages. After typing the first few characters of the <h:form> tag into the page, and hitting Ctrl+Space, we can take advantage of NetBeans' excellent code completion.

Java EE 6 Development with NetBeans 7

After adding the <h:form> tag and a number of additional JSF tags, our page now looks like this:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns=""
<h:outputStylesheet library="css" name="styles.css"/>
<h3>Registration Page</h3>
<h:panelGrid columns="3"
<h:outputLabel value="Salutation: " for="salutation"/>
<h:selectOneMenu id="salutation" label="Salutation"
value="#{registrationBean.salutation}" >
<f:selectItem itemLabel="" itemValue=""/>
<f:selectItem itemLabel="Mr." itemValue="MR"/>
<f:selectItem itemLabel="Mrs." itemValue="MRS"/>
<f:selectItem itemLabel="Miss" itemValue="MISS"/>
<f:selectItem itemLabel="Ms" itemValue="MS"/>
<f:selectItem itemLabel="Dr." itemValue="DR"/>
<h:message for="salutation"/>
<h:outputLabel value="First Name:" for="firstName"/>
<h:inputText id="firstName" label="First Name"
value="#{registrationBean.firstName}" />
<h:message for="firstName" />
<h:outputLabel value="Last Name:" for="lastName"/>
<h:inputText id="lastName" label="Last Name"
value="#{registrationBean.lastName}" />
<h:message for="lastName" />
<h:outputLabel for="age" value="Age:"/>
<h:inputText id="age" label="Age" size="2"
<h:message for="age"/>
<h:outputLabel value="Email Address:" for="email"/>
<h:inputText id="email" label="Email Address"
<h:message for="email" />
<h:commandButton id="register" value="Register"
action="confirmation" />

The following screenshot illustrates how our page will be rendered at runtime:

Java EE 6 Development with NetBeans 7

All JSF input fields must be inside an <h:form> tag. The <h:panelGrid> helps us to easily lay out JSF tags on our page. It can be thought of as a grid where other JSF tags will be placed. The columns attribute of the <h:panelGrid> tag indicates how many columns the grid will have, each JSF component inside the <h:panelGrid> component will be placed in an individual cell of the grid. When the number of components matching the value of the columns attribute (three in our example) has been placed inside <h:panelGrid>, a new row is automatically started.

The following table illustrates how tags will be laid out inside an <h:panelGrid> tag:

Java EE 6 Development with NetBeans 7

Each row in our <h:panelGrid> consists of an <h:outputLabel> tag, an input field, and an <h:message> tag.

The columnClasses attribute of <h:panelGrid> allows us to assign CSS styles to each column inside the panel grid, its value attribute must consist of a comma separated list of CSS styles (defined in a CSS stylesheet). The first style will be applied to the first column, the second style will be applied to the second column, the third style will be applied to the third column, so on and so forth. Had our panel grid had more than three columns, then the fourth column would have been styled using the first style in the columnClasses attribute, the fifth column would have been styled using the second style in the columnClasses attribute, so on and so forth.

If we wish to style rows in an <h:panelGrid>, we can do so with its rowClasses attribute, which works the same way that the columnClasses works for columns.

Notice the <h:outputStylesheet> tag inside <h:head> near the top of the page, this is a new tag that was introduced in JSF 2.0. One new feature that JSF 2.0 brings to the table is standard resource directories. Resources such as CSS stylesheets, JavaScript files, images, and so on, can be placed under a top level directory named resources, and JSF tags will have access to those resources automatically. In our NetBeans project, we need to place the resources directory under the Web Pages folder.

Java EE 6 Development with NetBeans 7

We then need to create a subdirectory to hold our CSS stylesheet (by convention, this directory should be named css), then we place our CSS stylesheet(s) on this subdirectory.

The value of the library attribute in <h:outputStylesheet> must match the directory where our CSS file is located, and the value of its name attribute must match the CSS file name.

In addition to CSS files, we should place any JavaScript files in a subdirectory called javascript under the resources directory. The file can then be accessed by the <h:outputScript> tag using "javascript" as the value of its library attribute and the file name as the value of its name attribute.

Similarly, images should be placed in a directory called images under the resources directory. These images can then be accessed by the JSF <h:graphicImage> tag, where the value of its library attribute would be "images" and the value of its name attribute would be the corresponding file name.

Now that we have discussed how to lay out elements on the page and how to access resources, let's focus our attention on the input and output elements on the page.

The <h:outputLabel> tag generates a label for an input field in the form, the value of its for attribute must match the value of the id attribute of the corresponding input field.

<h:message> generates an error message for an input field, the value of its for field must match the value of the id attribute for the corresponding input field. The first row in our grid contains an <h:selectOneMenu>. This tag generates an HTML <select> tag on the rendered page.

Every JSF tag has an id attribute, the value for this attribute must be a string containing a unique identifier for the tag. If we don't specify a value for this attribute, one will be generated automatically. It is a good idea to explicitly state the ID of every component, since this ID is used in runtime error messages. Affected components are a lot easier to identify if we explicitly set their IDs.

When using <h:label> tags to generate labels for input fields, or when using <h:message> tags to generate validation errors, we need to explicitly set the value of the id tag, since we need to specify it as the value of the for attribute of the corresponding <h:label> and <h:message> tags.

Every JSF input tag has a label attribute. This attribute is used to generate validation error messages on the rendered page. If we don't specify a value for the label attribute, then the field will be identified in the error message by its ID.

Each JSF input field has a value attribute, in the case of <h:selectOneMenu>, this attribute indicates which of the options in the rendered <select> tag will be selected. The value of this attribute must match the value of the itemValue attribute of one of the nested <f:selectItem> tags. The value of this attribute is usually a value binding expression, that means that the value is read at runtime from a JSF managed bean. In our example, the value binding expression #{registrationBean.salutation} is used. What will happen is at runtime JSF will look for a managed bean named registrationBean, and look for an attribute named salutation on this bean, the getter method for this attribute will be invoked, and its return value will be used to determine the selected value of the rendered HTML <select> tag.

Nested inside the <h:selectOneMenu> there are a number of <f:selectItem> tags. These tags generate HTML <option> tags inside the HTML <select> tag generated by <h:selectOneMenu>. The value of the itemLabel attribute is the value that the user will see while the value of the itemValue attribute will be the value that will be sent to the server when the form is submitted.

All other rows in our grid contain <h:inputText> tags, this tag generates an HTML input field of type text, which accept a single line of typed text as input. We explicitly set the id attribute of all of our <h:inputText> fields, this allows us to refer to them from the corresponding <h:outputLabel> and <h:message> fields. We also set the label attribute for all of our <h:inputText> tags, this results in more user-friendly error messages.

Some of our <h:inputText> fields require a value, these fields have their required attribute set to true, each JSF input field has a required attribute, if we need to require the user to enter a value for this attribute, then we need to set this attribute to true. This attribute is optional, if we don't explicitly set a value for it, then it defaults to false.

In the last row of our grid, we added an empty <h:panelGroup> tag. The purpose of this tag is to allow adding several tags into a single cell of an <h:panelGrid>. Any tags placed inside this tag are placed inside the same cell of the grid where <h:panelGrid> is placed. In this particular case, all we want to do is to have an "empty" cell in the grid so that the next tag, <h:commandButton>, is aligned with the input fields in the rendered page.

<h:commandButton> is used to submit a form to the server. The value of its value attribute is used to generate the text of the rendered button. The value of its action attribute is used to determine what page to display after the button is pressed.

In our example, we are using static navigation. When using JSF static navigation, the value of the action attribute of a command button is hard-coded in the markup.

When using static navigation, the value of the action attribute of <h:commandButton> corresponds to the name of the page we want to navigate to, minus its .xhtml extension. In our example, when the user clicks on the button, we want to navigate to a file named confirmation.xhtml, therefore we used a value of "confirmation" for its action attribute.

An alternative to static navigation is dynamic navigation. When using dynamic navigation, the value of the action attribute of the command button is a value binding expression resolving to a method returning a String in a managed bean. The method may then return different values based on certain conditions. Navigation would then proceed to a different page depending on the value of the method.

As long as it returns a String, the managed bean method executed when using dynamic navigation can contain any logic inside it, and is frequently used to save data in a managed bean into a database.

When using dynamic navigation, the return value of the method executed when clicking the button must match the name of the page we want to navigate to (again, minus the file extension).

In earlier versions of JSF, it was necessary to specify navigation rules in facesconfig.xml, with the introduction of the conventions introduced in the previous paragraphs, this is no longer necessary.



        Read more about this book      

(For more resources on Java, see here.)

Creating our managed bean

JSF managed beans are standard JavaBeans that are used to hold user-entered data in JSF applications.

In order to create a new managed bean, we need to go to File | New File..., select JavaServer Faces from the category list, and JSF Managed Bean from the file type list.

Java EE 6 Development with NetBeans 7

On the next screen in the wizard, we need to enter a name for our managed bean, as well as a package:

Java EE 6 Development with NetBeans 7

Most default values are sensible and in most cases can be accepted. The only one we should change if necessary is the Scope field.

Managed beans can have different scopes. A scope of request means that the bean is only available in a single HTTP request. Managed beans can also have session scope, in which case they are available in a single user's HTTP session. A scope of application means that the bean is accessible to all users in the application, across user sessions. Managed beans can also have a scope of none, which means that the managed bean is not stored at any scope, but is created on demand as needed. Additionally, managed beans can have a scope of view, in which case the bean is available until the user navigates to another page. View scoped managed beans are available across Ajax requests.

We should select the appropriate scope for our managed bean, in our particular example, the default request scope will meet our needs.

After finishing the wizard, a boilerplate version of our managed bean is created in the specified package.

The generated managed bean source simply consists of the annotated managed bean class containing a single public no argument constructor.

package com.ensode.jsf.managedbeans;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
public class RegistrationBean {
/** Creates a new instance of RegistrationBean */
public RegistrationBean() {

The @ManagedBean annotation marks the class as a JSF managed bean. By default, the managed bean name defaults to the class name (RegistrationBean, in our case) with its first character switched to lower case (registrationBean, in our case). If we want to override the default name, we can do it by specifying a different name in the NetBeans New JSF Managed Bean wizard, or by simply setting the name attribute of @ManagedBean to the desired value. In general, sticking to the defaults allows for more readable and maintainable code therefore we shouldn't deviate from them unless we have a good reason.

With the addition of any Java class annotated with @ManagedBean in our project, we no longer need to register FacesServlet in web.xml as the JSF runtime in the application server will automatically register the servlet.

The @RequestScoped annotation designates that our managed bean will have a scope of request. Had we selected a different scope when creating the managed bean with the NetBeans wizard, it would have been annotated with the appropriate annotation corresponding to the selected scope. Session scoped managed beans are annotated with the @SessionScoped annotation. Application scoped managed beans are annotated with the @ApplicationScoped annotation. Managed beans with a scope of "none", are annotated with the @NoneScoped annotation. View scoped managed beans are annotated with the @ViewScoped annotation. At this point, we need to modify our managed bean by adding properties that will hold the user-entered values.

Automatic Generation of Getter and Setter Methods
Netbeans can automatically generate getter and setter methods for our properties. We simply need to click the keyboard shortcut for "insert code", which defaults to Alt+Insert in Windows and Linux, then select Getters and Setters.

package com.ensode.jsf.managedbeans;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.RequestScoped;
public class RegistrationBean {
/** Creates a new instance of RegistrationBean */
public RegistrationBean() {
private String salutation;
private String firstName;
private String lastName;
private Integer age;
private String email;
//getters and setters omitted for brevity

Notice that the names of all of the bean's properties (instance variables) match the names we used in the page's value binding expressions. These names must match so that JSF knows how to map the bean's properties to the value binding expressions.

Implementing the confirmation page

Once our user fills out the data on the input page and submits the form, we want to show a confirmation page displaying the values that the user entered. Since we used value binding expressions on every input field on the input page, the corresponding fields on the managed bean will be populated with user-entered data. Therefore all we need to do in our confirmation page is display the data on the managed bean via a series of <h:outputText> JSF tags.

We can create the confirmation page via the New JSF File wizard.

Java EE 6 Development with NetBeans 7

We need to make sure the name of the new file matches the value of the action attribute in the command button of the input page (confirmation.xhtml) so that static navigation works properly.

After modifying the generated page to meet the requirements, it should look like this:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
<html xmlns=""
<title>Confirmation Page</title>
<h:outputStylesheet library="css" name="styles.css"/>
<h2>Confirmation Page</h2>
<h:panelGrid columns="2"
<h:outputText value="Salutation: "/>
value="#{registrationBean.salutation}" />
<h:outputText value="First Name:"/>
<h:outputText value="#{registrationBean.firstName}" />
<h:outputText value="Last Name:"/>
<h:outputText value="#{registrationBean.lastName}" />
<h:outputText value="Age:"/>
<h:outputText value="#{registrationBean.age}"/>
<h:outputText value="Email Address:"/>
<h:outputText value="#{}" />

As we can see, our confirmation page is very simple. It consists of a series of <h:outputText> tags containing labels and value binding expressions bound to our managed bean's properties. The JSF <h:outputText> tag simply displays the value of the expression of its value attribute on the rendered page.

Executing our application

We are now ready to execute our JSF application. The easiest way to do so is to right-click on our project and click on Run in the resulting pop up menu.

At this point GlassFish (or whatever application server we are using for our project) will start automatically, if it hadn't been started already, the default browser will open and it will automatically be directed to our page's URL.

After entering some data on the page, it should look something like the following screenshot:

Java EE 6 Development with NetBeans 7

When we click on the Register button, our RegistrationBean managed bean is populated with the values we entered into the page. Each property in the field will be populated according to the value binding expression in each input field.

At this point JSF navigation "kicks in", and we are taken to the confirmation page.

Java EE 6 Development with NetBeans 7

The values displayed in the confirmation page are taken from our managed bean, confirming that the bean's properties were populated correctly.

JSF validation

Earlier in this article we discussed how the required attribute for JSF input fields allows us to easily make input fields mandatory.

If a user attempts to submit a form with one or more required fields missing, an error message is automatically generated.

Java EE 6 Development with NetBeans 7

The error message is generated by the <h:message> tag corresponding to the invalid field. The string "First Name" in the error message corresponds to the value of the label attribute for the field, had we omitted the label attribute, the value of the field's id attribute would have been shown instead. As we can see, the required attribute makes it very easy to implement mandatory field functionality in our application.

Recall that the age field is bound to a property of type Integer in our managed bean. If a user enters a value that is not a valid integer into this field, a validation error is automatically generated.

Java EE 6 Development with NetBeans 7

Of course, a negative age wouldn't make much sense. However, our application validates that user input is a valid Integer with essentially no effort on our part.

The email address input field of our page is bound to a property of type String in our managed bean. As such, there is no built in validation to make sure that the user enters a valid email address. In cases like this, we need to write our own custom JSF validator.

Custom JSF validators must implement the javax.faces.validator.Validator interface. This interface contains a single method named validate(), this method takes three parameters, an instance of javax.faces.context.FacesContext, an instance of javax.faces.component.UIComponent containing the JSF component we are validating, and an instance of java.lang.Object containing the user-entered value for the component. The following example illustrates a typical custom validator:

package com.ensode.jsf.validators;

import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.faces.application.FacesMessage;
import javax.faces.component.UIComponent;
import javax.faces.component.html.HtmlInputText;
import javax.faces.context.FacesContext;
import javax.faces.validator.Validator;
import javax.faces.validator.ValidatorException;
public class EmailValidator implements Validator {
public void validate(FacesContext facesContext,
UIComponent uIComponent, Object value) t
ValidatorException {
Pattern pattern = Pattern.compile("\\w+@\\w+\\.\\w+");
Matcher matcher = pattern.matcher(
(CharSequence) value);
HtmlInputText htmlInputText =
(HtmlInputText) uIComponent;
String label;

if (htmlInputText.getLabel() == null ||
htmlInputText.getLabel().trim().equals("")) {
label = htmlInputText.getId();
} else {
label = htmlInputText.getLabel();
if (!matcher.matches()) {
FacesMessage facesMessage =
new FacesMessage(label +
": not a valid email address");
throw new ValidatorException(facesMessage);

In our example, the validate() method does a regular expression match against the value of the JSF component we are validating. If the value matches the expression, validation succeeds, otherwise, validation fails and an instance of javax.faces.validator.ValidatorException is thrown.

The primary purpose of our custom validator is to illustrate how to write custom JSF validations, and not to create a foolproof email address validator. There may be a valid email address that doesn't validate using our validator.

The constructor of ValidatorException takes an instance of javax.faces.application.FacesMessage as a parameter. This object is used to display the error message on the page when validation fails. The message to display is passed as a String to the constructor of FacesMessage. In our example, if the label attribute of the component is not null nor empty, we use it as part of the error message, otherwise we use the value of the component's id attribute. This behavior follows the pattern established by standard JSF validators.

Our validator needs to be annotated with the @FacesValidator annotation. The value of its value attribute is the ID that will be used to reference our validator in our JSF pages.

Once we are done implementing our validator, we are ready to use it in our pages.

In our particular case, we need to modify the email field to use our custom validator.

<h:inputText id="email" label="Email Address"
required="true" value="#{}">
<f:validator validatorId="emailValidator"/>

All we need to do is nest a <f:validator> tag inside the input field we wish to have validated using our custom validator. The value of the validatorId attribute of <f:validator> must match the value of the value attribute in the @FacesValidator annotation in our validator.

At this point we are ready to test our custom validator.

Java EE 6 Development with NetBeans 7

When entering an invalid email address into the email address input field and submitting the form, our custom validator logic was executed and the String we passed as a parameter to FacesMessage in our validator() method is shown as the error text by the <h:message> tag for the field.


In this article we saw how NetBeans can help us easily create new JSF projects by automatically adding all required libraries. We saw how we can quickly create JSF pages by taking advantage of NetBeans' code completion.

Further resources on this subject:

Books to Consider

JSF 2.0 Cookbook: LITE
$ 9.99
Getting Started with CreateJS
$ 17.99
.Net Framework 4.5 Expert Programming Cookbook
$ 29.99
comments powered by Disqus

An Introduction to 3D Printing

Explore the future of manufacturing and design  - read our guide to 3d printing for free