Getting started with jstl labels: El: Expression Language

Source: Internet
Author: User
Tags cookie names map class

Getting started with jstl: Expression Language
Simplify software maintenance for JSP applications by avoiding scripting Elements

JSP standard tag Library (jstl) is a set of custom tag libraries that implement common functions in Web applications, these functions include iteration and condition judgment, data management formatting, XML operations, and database access. In the first article in his new series on developerworks, software engineer Mark Kolb showed you how to use jstl tags to avoid scripting elements on JSP pages. You will also learn how to simplify software maintenance by deleting source code from the presentation layer. Finally, you will understand the simplified Expression Language of jstl, which allows you to specify dynamic attribute values for jstl operations without having to use a fully functional programming language.
Assumerver pages (JSP) is a standard presentation layer technology for the J2EE platform. JSP technology provides script elements and operations for executing computation (These computation is used to dynamically generate page content. The script element allows you to include the program source code on the JSP page, which can be executed when the page is displayed in response to user requests. Operations encapsulate computing operations into tags like HTML or XML tags. The template text of a JSP page usually contains these tags. The JSP Specification defines only several operations as standards. However, starting from JSP 1.1, developers have been able to create their own operations in the form of custom tag libraries.

JSP standard tag Library (jstl) is a set of custom tag libraries for JSP 1.2. These tag libraries implement common basic functions for a large number of server-side Java applications. By providing standard implementation for typical presentation layer tasks (such as data formatting and iteration or condition content), jstl enables JSP authors to focus on application-specific development needs, instead of "getting started" for these general operations ".

Of course, you can use JSP scripts to compile elements (scriptlet, expressions, and declarations) to implement such tasks. For example, three scriptlets can be used to implement the Condition content. The three scriptlets are highlighted in Listing 1. However, because scripting elements depend on embedding program source code (usually Java code) in the page, for JSP pages that use these scripts to compile elements, the complexity of software maintenance tasks is greatly increased. For example, the scriptlet example in Listing 1 strictly depends on the correct matching of curly braces. If a syntax error is inadvertently introduced, nesting other scriptlets in the Condition content may cause serious damage, and when the JSP Container compiles the page, it may be difficult to make the error information meaningful.

Listing 1. Using scriptlet to implement conditional content
<% IF (user. getrole () = "member") {%>
<P> welcome, member! </P>
<%} Else {%>
<P> welcome, guest! </P>
<% }%>

Fixing such problems usually requires a wealth of programming experience. Although JSP is usually developed and maintained by designers who are very proficient in page layout and graphic design, programmers are required to intervene when the script elements on the same page are faulty. In this situation, the Code responsibilities in a single file are shared to many people, making it a very troublesome task to develop, debug, and enhance such JSP pages. By packaging common functions into the standard set of custom tag libraries, jstl allows JSP authors to reduce the need to compile script elements, or even skip them, and avoid related maintenance costs.

Jstl 1.0

Jstl 1.0 was released in June 2002 and consists of four custom tag libraries (core, format, XML, and SQL) and a pair of common tag library validators (scriptfreetlv and permittedtaglibstlv. The core tag Library provides custom operations to manage data by limiting the scope of variables, as well as performing page content iterations and conditional operations. It also provides tags for generating and operating URLs. As the name implies, the format tag library defines operations for formatting data (especially numbers and dates. It also supports internationalization of JSP pages using localized resource bundle. The XML library contains some tags that are used to manipulate data expressed in XML, while the SQL database defines the operations used to query relational databases.

The two jstl tag library validators allow developers to enforce encoding standards in their JSP applications. You can configure the scriptfreetlv validators to disable various types of JSP script elements-scriptlet, expressions, and declarations on the JSP page. Similarly, the permittedtaglibstlv validator can be used to restrict the custom tag Library (including the jstl tag Library) that may be accessed by the application's JSP page ).

Although jstl will eventually become a required component of the J2EE platform, only a few application servers currently include it. The reference implementation of jstl 1.0 can be obtained as part of the Jakarta taglibs project of the Apache Software Foundation (see references. You can merge the custom tag library in the reference implementation to any server that supports the JSP 1.2 and Servlet 2.3 specifications to add support for jstl.

In JSP 1.2, you can use static strings or expressions (if allowed) to specify attributes of JSP operations. For example, in Listing 2, a static value is specified for the name and property attributes of the <JSP: setproperty> operation, and its value attribute is specified using an expression. The effect of this operation is to assign the current value of the request parameter to the bean feature named. The expression used in this form is called the request-time attribute value, which is the only mechanism used to dynamically specify the attribute value in the JSP specification.

List 2. jsp operation of attribute values when merging requests
<JSP: setproperty name = "user" property = "timezonepref"
Value = '<% = request. getparameter ("timezone") %>'/>

Because the attribute values are specified by expressions during a request, they often have the same software maintenance problems as other script elements. Therefore, jstl supports another mechanism for specifying dynamic attribute values. You can use a simplified Expression Language (EL) instead of a complete JSP expression to specify the attribute value of a jstl operation. El provides identifiers, accessors, and operators to retrieve and operate data residing in the JSP Container. To some extent, El is based on ecmascript (see references) and XML Path Language (XPath). Therefore, both page designers and programmers should be familiar with its syntax. El is good at searching for objects and their features, and then performing simple operations on them; it is not a programming language or even a scripting language. However, when used together with the jstl mark, it can use simple and convenient symbols to express complex behavior. The El expression format is as follows: it is bounded by the dollar sign ($) and the content is included in curly brackets ({}), as shown in listing 3.

Listing 3. describes the jstl operations of the El expression delimiters.
<C: Out value = "$ {user. firstname}"/>

In addition, you can combine multiple expressions with static text to construct dynamic attribute values through String concatenation, as shown in Listing 4. A separate expression consists of an identifier, accessor, text, and operator. An identifier is used to reference data objects stored in a data center. El has 11 retained identifiers, corresponding to 11 El implicit objects. Assume that all other identifiers reference variables with limited scopes. Accessors are used to retrieve the characteristics or elements of an object. Text represents a fixed value-number, character, String, Boolean, or null. Operators allow combination and comparison of data and text.

Listing 4. combining static text and multiple El expressions to specify dynamic attribute values
<C: Out value = "Hello $ {user. firstname }$ {user. lastname}"/>

Variables with limited scope

The jsp api allows you to store and retrieve data from four different scopes in the JSP Container through the <JSP: usebean> operation. Jstl extends this capability by providing additional operations for specifying and removing objects in these scopes. In addition, El provides built-in support for searching these objects as variables with limited scopes. In particular, any identifier that appears in an El expression but does not conform to any El implicit object is automatically assumed to reference an object stored in one of the four JSP scopes, the four scopes are:

Page Scope
Request Scope
Session Scope
Application Scope
You may remember that only objects stored in the page scope can be retrieved during the processing of a specific request page. If the object is stored in the request scope, these objects can be retrieved during processing of all pages involved in processing a request (for example, one or more <JSP: Include> or <JSP: forward> operation ). If the object is stored in the session scope, during the interactive session with the web application, it can be retrieved by any page accessed by the user (that is, until the httpsession object associated with the user is invalid ). Any user can access objects stored in the application scope from any page until the web application itself is uninstalled (usually due to the closure of the JSP Container ).

Objects are stored in the expected scope by ing strings to objects in the expected scope. Then, the object can be retrieved from the scope by providing the same string. Search for the string in the ing of the scope and return the mapped object. In servlet APIs, such objects are called attributes of corresponding scopes. However, in the context of El, the string associated with the attribute is also considered as the name of the variable. The variable obtains the specific value through attribute ing.

In El, the identifier that is not associated with the implicit object is considered to be the name object stored in four JSP scopes. First, check whether such an identifier exists in the page scope, and then check the request scope, session scope, and application scope in sequence, then, test whether the name of the identifier matches the name of an object stored in the scope. The first such match is returned as the value of the El identifier. In this way, the El identifier can be viewed as a variable that references a limited scope.

More technically, the identifiers not mapped to the implicit object are evaluated using the findattribute () method of the pagecontext instance. This instance indicates page processing. on this page, the expression currently processing the request. The identifier name is passed to this method as a parameter, and then the method searches for attributes with the same name in four scopes in sequence. Return the first matched item as the findattribute () method value. If this attribute is not found in the Four Scopes, null is returned.

Ultimately, variables that limit the scope are attributes of four JSP scopes, which have names that can be used as El identifiers. You only need to assign a name consisting of letters and numbers to variables with limited scopes to create them through any mechanism provided in JSP for setting attributes. This includes the built-in <JSP: usebean> operations and the setattribute () method defined by several classes in the servlet API. In addition, many custom tags defined in the four jstl libraries can be set as attribute values used as variables that limit the scope.

Implicit object

Table 1 lists 11 El implicit object identifiers. Do not confuse these objects with JSP implicit objects (only nine in total). Only one of these objects is shared by them.

Table 1. El implicit object

CATEGORY identifier description
The JSP pagecontext instance corresponds to the processing of the current page
Map class associated with the names and values of the pagination scope and page scope attributes
Map class associated with the names and values of requestscope and request scope attributes
Map class associated with the names and values of sessionscope and session scope attributes
Map class associated with the names and values of applicationscope attributes and application scope attributes
Request Parameter Param stores the map class of the main values of Request Parameters by name
Paramvalues uses all the values of request parameters as the map class stored in the string array.
The request header stores the map class of the main value of the Request Header by name.
Headervalues uses all the values in the Request Header as the map class stored in the string array.
Cookie cookie store the map class of the cookie included in the request by name
The initialization parameter initparam stores the map class of the Web application context initialization parameter by name

Although there is only one common object (pagecontext) in JSP and El implicit objects, other JSP implicit objects can be accessed through El. The reason is that pagecontext has the ability to access all the other eight JSP implicit objects. In fact, this is the main reason to include it in the El implicit object.

All other El implicit objects are mapped and can be used to find the objects corresponding to the name. The first four mappings indicate various attribute scopes discussed previously. They can be used to find identifiers in a specific scope, instead of relying on the sequential lookup process used by El by default.

The next four mappings are used to obtain the values of Request Parameters and request headers. Because HTTP allows Request Parameters and request headers to have multiple values, each of them has a ing relationship. The first ing in each pair returns the main value of the request parameter or header, which usually happens to be the value specified first in the actual request. The second ing of each pair allows you to retrieve all values of a parameter or header. The keys in these mappings are the names of parameters or headers, but these values are arrays of string objects. Each element is a single parameter value or header value.

The cookie implicit object provides access to the cookie name set by the request. This object maps all cookie names associated with the request to Cookie objects that represent the cookie features.

The last El implicit object initparam is a ing that stores the names and values of initialization parameters for all contexts associated with the Web application. The initialization parameter is specified through the Web. xml deployment descriptor file, which is located in the WEB-INF directory of the application.

Accessors

Because El identifiers are parsed as implicit objects or variables with limited scopes (implemented through attributes), it is necessary to convert them into Java objects. El can automatically wrap and unwrap the basic types in corresponding Java classes (for example, int can be forcibly converted to integer classes in the background, or vice versa ), however, most identifiers will be pointers to complete Java objects.

As a result, access to the features of these objects or elements of these objects (when the objects are arrays and collections) is usually satisfactory. To achieve this purpose, El provides two different accessors (vertex operators (.) and square brackets ([]), and supports features and elements through El operations.

Point operators are usually used to access the characteristics of objects. For example, in the expression $ {user. firstname}, use the dot operator to access the firstname feature of the object referenced by the User Identifier. El uses the Java Bean convention to access the object feature. Therefore, the getter method of this feature must be defined (usually the method named getfirstname () so that the expression can be correctly evaluated. When the accessed feature itself is an object, the vertex operator can be recursively applied. For example, if the fictitious user object has an address feature implemented as a Java object, you can also use the dot operator to access the features of this object. For example, expression $ {user. Address. City} returns the nested city feature of this address object.

The square brackets operator is used to retrieve elements of arrays and collections. When an array and an ordered set (that is, a set of Java. util. List interfaces) are implemented, place the subscript of the element to be retrieved in square brackets. For example, the expression $ {URLs [3]} returns the array referenced by the URLs identifier or the fourth element of the Set (same as in Java and JavaScript, the subscript in El starts from scratch ).

For a set that implements the java. util. map interface, the square brackets operator uses the associated key to find the value stored in the ing. Specify the key in square brackets and return the corresponding value as the expression value. For example, expression $ {commands ["dir"]} returns the value associated with the "dir" key in the Map referenced by the commands identifier.

Both of the preceding conditions allow expressions to appear in square brackets. Evaluate the nested expression as a subscript or key to retrieve the appropriate elements of a set or array. Like the dot operator, the square brackets operator can also be applied recursively. This allows El to retrieve elements from multi-dimensional arrays, Nested Sets, or any combination of the two. In addition, vertex operators and square brackets operators can interoperate. For example, if an array element is an object, you can use the square brackets operator to retrieve the elements of the array, and combine operators to retrieve a feature of this element (for example, $ {URLs [3]. protocol }).

Assuming that El acts as a simplified language for specifying dynamic attribute values, the El accessors have an interesting feature (different from the Java accessors), that is, they do not throw an exception when applied to null. If you apply the El accessors (for example, $ {Foo. the Foo identifier in bar} and $ {Foo ["bar"]} is null, so the application accessors return null. It turns out that in most cases this is a very useful behavior and you will soon understand this.

Finally, vertex operators and square brackets operators may be interchangeable to some extent. For example, you can use $ {user ["firstname"]} to retrieve the firstname feature of the user object, just as you can use $ {commands. dir} gets the same value associated with the "dir" key in the commands ing.

Operator

El can also use identifiers and accessors to traverse object hierarchies that contain application data (exposed by variables with limited scopes) or information about the environment (through El implicit objects. However, accessing the data is usually not enough to implement the representation logic required by many JSP applications.

In the end, El also includes several operators used to operate and compare the data accessed by El expressions. Table 2 summarizes these operators.

Table 2. El Operators

CATEGORY Operators
Arithmetic Operators +,-, *,/(or Div), and % (or mod)
Relational operators = (or eq ),! = (Or NE), <(or LT),> (or Gt), <= (or Le), and> = (or GE)
Logical operators & (or and), | (or), and! (Or not)
Verification operator empty

Arithmetic Operators support addition, subtraction, multiplication, and division of values. A Remainder operator is also provided. Note: Division and Division operators both have alternative and unsigned names (to be consistent with XPath ). Listing 5 shows an example expression that demonstrates the usage of arithmetic operators. The result of applying Arithmetic Operators to several El expressions is the result of applying the arithmetic operators to the values returned by these expressions.

Listing 5. El expressions using Arithmetic Operators
$ {Item. Price * (1 + taxrate=user.address.zip Code])}

Relational operators allow comparison of numeric or text data. Returns the result of comparison as a Boolean value. Logical operators allow merging boolean values and return new Boolean values. Therefore, you can apply El logical operators to nested relationships or logical operators, as shown in Listing 6.

Listing 6. El expressions using relational and logical operators
$ {(X> = min) & (x <= max )}

The last El operator is empty, which is particularly useful for data verification. The empty operator uses a single expression as its variable (that is, $ {empty input}) and returns a Boolean value, this Boolean value indicates whether the result of the evaluation of the expression is "null. A null expression is considered null, that is, a set or array without elements. If the parameter is the result of a string with zero length, the empty operator returns true.

Table 3 lists the priority of the El operator. As shown in listing 5 and 6, you can use parentheses to group expressions, which are higher than normal priority rules.

Table 3. El operator priority (from top to bottom, from left to right)

[],.
()
Unary-, not ,! , Empty
*,/, Div, %, MOD
+, Binary-
() </Code>,>, <=,> =, LT, GT, le, Ge
= ,! =, EQ, ne
&, And
|, Or

Text

In El expressions, numbers, strings, Boolean values, and null can all be specified as text values. A string can be enclosed by single or double quotation marks. Boolean values are specified as true and false.

Taglib pseudocommand

As we discussed earlier, jstl 1.0 includes four custom tag libraries. To demonstrate the interaction between the jstl tag and the expression language, we will study several tags from the jstl core library. Like using any JSP custom tag library, you must include the taglib pseudo command on any page that you want to use this library tag. Listing 7 shows the pseudocommands used for this particular library.

Listing 7. taglib pseudocommands used for the El version of The jstl core library
<% @ Taglib uri = "http://java.sun.com/jstl/core" prefix = "C" %>

In fact, there are two types of taglib pseudo commands corresponding to the jstl core library, because El is optional in jstl 1.0. All four jstl 1.0 custom tag libraries use JSP expressions (instead of El) to specify the standby version of the dynamic attribute value. Because these slave libraries depend on JSP's more traditional request-time attribute values, they are called RT libraries, and those using expression languages are called El libraries. Developers use different taglib commands to differentiate the two versions of each database. Listing 8 shows the pseudocommands that use the RT version of the core database. However, since the focus of our discussion is El, we need these pseudo commands first.

Listing 8. taglib pseudocommands used for the RT version of The jstl core library
<% @ Taglib uri = "http://java.sun.com/jstl/core_rt" prefix = "c_rt" %>

Variable tag

The jstl custom tag is the <C: Set> operation. As has been noted, variables with limited scopes play a key role in jstl. The <C: Set> operation provides a tag-based mechanism to create and set variables with limited scopes. The syntax of this operation is displayed in listing 9. The VaR attribute specifies the name of the variable that limits the scope, and the scope attribute indicates the scope in which the variable resides, the Value Attribute specifies the value assigned to this variable. If the specified variable already exists, simply assign the specified value to it. If the variable does not exist, create a new variable that limits the scope and use this value to initialize the variable.

Listing 9. <C: Set> operation syntax
<C: Set Var ="
Name "Scope ="
Scope "value ="
Expression "/>

The scope attribute is optional, and the default value is page.

The two examples of <C: Set> are shown in listing 10. In the first example, set the session scope variable to a string value. In the second example, use an expression to set the value: Assign the square variable in the page scope to the square of the value of the request parameter named X.

Listing 10. <C: Set> operation example
<C: Set Var = "timezone" Scope = "session" value = "CST"/>
<C: Set Var = "square" value = "$ {Param ['X'] * Param ['X']}"/>

You can also specify the value of a variable with a limited scope as the subject content of the <C: Set> operation, rather than using attributes. With this method, you can rewrite the first example in listing 10, as shown in listing 11. In addition, as we can see right away, the content of the subject marked by <C: Set> can also be customized. <C: Set> all content generated in the subject is assigned to the specified variable as a string value.

Listing 11. specifying the <C: Set> operation value through the subject content
<C: Set Var = "timezone" Scope = "session"> CST </C: Set>

The jstl core library contains the second tag used to manage variables with limited scopes-<C: Remove>. As the name suggests, the <C: Remove> operation is used to delete a variable with a limited scope. It gets two attributes. The VaR attribute specifies the name of the variable to be deleted. The scope attribute is optional. It indicates the scope of the variable to be deleted. The default value is page, as shown in listing 12.

Listing 12. <C: Remove> operation example <C: Remove Var = "timezone" Scope = "session"/>

Output

Although the <C: Set> operation allows the expression result to be assigned to a variable with a limited scope, developers usually want to display only the value of the expression, rather than store it. The jstl <C: Out> custom tag undertakes this task. The syntax is shown in listing 13. This tag evaluates the expression specified by its value attribute and then prints the result. If the optional attribute default is specified, <C: Out> prints the value if the result obtained by evaluating the expression of the value attribute is null or a null string.

Listing 13. <C: Out> operation syntax
<C: Out value ="
Expression "default ="
Expression "escapexml ="
Boolean "/>

The escapexml attribute is also optional. It controls the use of <C: Out> to mark the output of characters such as "<", ">", and "&" (which has special significance in HTML and XML) whether to escape. If you set escapexml to true, these characters are automatically converted to the corresponding XML entity (the characters mentioned here are converted to <,>, and & respectively &).

For example, assume that there is a session scope variable named user, which is an instance of a class and defines two features for the user: username and company. This object is automatically assigned to sessions when a user accesses the site, but these two features are not set until the user actually logs on. For this solution, consider the JSP snippets in listing 14. After a user logs on, the clip displays the word "hello", followed by his/her username and an exclamation point. However, before a user logs on, the content generated by this clip is the phrase "Hello guest !". In this case, because the username feature is still to be initialized, the <C: Out> flag will print the value of the default attribute (that is, the string "guest ").

Listing 14. <C: Out> operation example with default content
Hello <C: Out value = "$ {user. Username}" default = "guest"/>!

Next, consider listing 15, which uses the escapexml attribute marked by <C: Out>. If the company feature has been set to Java string value "Flynn & Sons" in this case, the actual content generated by this operation will be Flynn & Sons. If this operation is part of a JSP page that generates HTML or XML content, the "&" symbol in the string may eventually be interpreted as an HTML or XML control character, this hinders the display or resolution of the content. However, if you set the escapexml attribute value to true, the generated content will be Flynn & Sons. The browser or parser will not cause problems when interpreting this content. Assuming that HTML and XML are the most common content types in JSP applications, it is not surprising that the default value of the escapexml attribute is true.

Listing 15. Example of disabling escape operations
<C: Out value = "$ {user. Company}" escapexml = "false"/>

Set variables with default values

In addition to simplifying the display of dynamic data, you can use <C: Set> to set variable values, <C: Out> to specify the default value. As shown in listing 11, the value assigned to a variable with a limited scope can be specified as the subject content marked by <C: Set> or its value attribute. By embedding the <C: Out> operation in the subject content marked by <C: Set>, the default value of the variable can be used to assign values.

This method is described in listing 16. The behavior of the external <C: Set> flag is very simple: it sets the value of the timezone variable in the session scope according to its body content. However, in this case, the subject content is generated through the <C: Out> operation. The Value Attribute of this nested operation is the expression $ {cookie ['tzpref']. Value}. It tries to return the cookie value named tzpref through the cookie implicit object. (The cookie implicit object maps the cookie name to the corresponding cookie instance, which means that the actual data stored in the cookie must be retrieved using the dot operator through the value feature of the object .)

Listing 16. Merge <C: Set> and <C: Out> to provide the default variable value.
<C: Set Var = "timezone" Scope = "session">
<C: Out value = "$ {cookie ['tzpref']. Value}" default = "CST"/>
</C: Set>

However, consider the following: this is the first time you try a web application using this code. The result is that no cookie named tzpref is provided in the request. This means that the query using an implicit object will return NULL. In this case, the entire expression will return null. Because the result of the Value Attribute of the <C: Out> tag is null, the <C: Out> tag returns the result of the default attribute. Here is the string Cst. Therefore, the actual result is to set the variables restricted by timezone to the time zone stored in the user's tzpref cookie, or, if not, use the default time zone Cst.

El and JSPs 2.0

Currently, the expression language can only be used to specify the dynamic attribute values in the jstl custom tag. However, an extension of the jstl 1.0 expression language has been proposed and will include it in JSP 2.0. The final review is currently underway. This extension allows developers to use el with their own custom tags. Page authors can use el expressions wherever JSP expressions are currently allowed, such as inserting dynamic values into template text: <p> your preferred time zone is $ {timezone} </P>.

This JSP 2.0 feature (just like jstl itself) will support page authors to further reduce the dependency on JSP script elements, thus improving the maintainability of JSP applications.

Conclusion

El (combined with the operations provided by four jstl custom tag libraries) allows page authors to implement presentation layer logic without using script elements. For example, compare the JSP code in Listing 1 at the beginning of this article with the same functions shown in listing 17 through jstl. (The remaining tags in the jstl core library, including <C: Choose> and Its subtags, will be discussed in the next article in this series .) Although the conditional logic is clearly executed, the jstl version does not have the source code of the Java language and the relationship between tags (especially for nesting requirements) anyone familiar with HTML syntax should be familiar with it.

Listing 17. Merge <C: Set> and <C: Out> to provide the default variable value.
<C: Choose> <C: When test = "$ {user. Role = 'member'}">
<P> welcome, member! </P>
</C: When> <C: otherwise>
<P> welcome, guest! </P>
</C: otherwise> </C: Choose>

By providing standard implementations for common functions of most web applications, jstl helps accelerate the development cycle. Combined with El, jstl does not need to write code for the presentation layer program, which greatly simplifies the maintenance of JSP applications.

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.