This practical can be completed in a 3-hour session.
This installation and configuration guide is applicable to Tomcat 7 and 8, and possibly the earlier versions.
Take note that Tomcat 8 requires JDK 1.7. It will NOT work with JDK 1.6. If your JDK is below 1.7, upgrade it (See JDK How-To). You can check your JDK version via command "javac -version
".
Introduction
Web Application (Webapp)
A web application (or webapp), unlike standalone application, runs over the Internet. Examples of webapps are google, amazon, ebay, facebook and twitter.
A webapp is typically a 3-tier (or multi-tier) client-server database application run over the Internet as illustrated in the diagram below. It comprises five components:
- HTTP Server: E.g., Apache HTTP Server, Apache Tomcat Server, Microsoft Internet Information Server (IIS), nginx, Google Web Server (GWS), and others.
- HTTP Client (or Web Browser): E.g., Internet Explorer (MSIE), FireFox, Chrome, Safari, and others.
- Database: E.g., Open-source MySQL, Apache Derby, mSQL, SQLite, PostgreSQL, OpenOffice's Base; Commercial Oracle, IBM DB2, SAP SyBase, MS SQL Server, MS Access; and others.
- Client-Side Programs: could be written in HTML Form, JavaScript, VBScript, Flash, and others.
- Server-Side Programs: could be written in Java Servlet/JSP, ASP, PHP, Perl, Python, CGI, and others.
The typical use-case is:
- A user, via a web browser (HTTP client), issues a URL request to an HTTP server to start a webapp.
- A client-side program (such as an HTML form) is loaded into client's browser.
- The user fills up the query criteria in the form.
- The client-side program sends the query parameters to a server-side program.
- The server-side program receives the query parameters, queries the database and returns the query result to the client.
- The client-side program displays the query result on the browser.
- The process repeats.
Hypertext Transfer Protocol (HTTP)
- HTTP is an application layer protocol runs over TCP/IP. The IP provides support for routing and addressing (via an unique IP address for machines on the Internet); while TCP supports multiplexing via 64K ports from port number 0 to 65535. The default port number assigned to HTTP is TCP port 80.
- HTTP is an asynchronous request-response application-layer protocol. A client sends a request message to the server. The server then returns a response message to the client.
- HTTP is a pull protocol, a client pulls a page from the server (instead of server pushes pages to the clients).
- The syntax of the message is defined in the HTTP specification.
Apache Tomcat HTTP Server
Apache Tomcat is a Java-capable HTTP server, which could execute special Java programs known as Java Servlet and Java Server Pages (JSP). It is the official Reference Implementation (RI) for Java Servlets and JavaServer Pages (JSP) technologies. Tomcat is an open-source project, under the "Apache Software Foundation" (which also provides the most use, open-source, industrial-strength Apache HTTP Server). The mother site for Tomcat is http://tomcat.apache.org. Alternatively, you can find tomcat via the Apache mother site @ http://www.apache.org.
Tomcat was originally written by James Duncan Davison (then working in Sun), in 1998, based on an earlier Sun's server called Java Web Server (JWS). It began at version 3.0 after JSWDK 2.1 it replaced. Sun subsequently made Tomcat open-source and gave it to Apache.
The various Tomcat releases are:
- Tomcat 3.x (1999): RI for Servlet 2.2 and JSP 1.1.
- Tomcat 4.x (2001): RI for Servlet 2.3 and JSP 1.2.
- Tomcat 5.x (2002): RI for Servlet 2.4 and JSP 2.0.
- Tomcat 6.x (2006): RI for Servlet 2.5 and JSP 2.1.
- Tomcat 7.x (2010): RI for Servlet 3.0, JSP 2.2 and EL 2.2.
- Tomcat 8.x (2013): RI for Servlet 3.1, JSP 2.3, EL 3.0 and Java WebSocket 1.0.
Tomcat is an HTTP application runs over TCP/IP. In other words, the Tomcat server runs on a specific TCP port in a specific IP address. The default TCP port number for HTTP protocol is 80, which is used for the production HTTP server. For test HTTP server, you can choose any unused port number between 1024 and 65535.
How to Install Tomcat 8 and Get Started with Java Servlet Programming
STEP 1: Download and Install Tomcat
NOTE: At the time of writing, Tomcat 9 is at the alpha stage, not stable release. We shall install Tomcat 8.0.30.
For Windows
- Goto http://tomcat.apache.org ⇒ Downloads ⇒ Tomcat 8.0 ⇒ "
8.0.{xx}
" (where{xx}
is the latest upgrade number) ⇒ Binary Distributions ⇒ Core ⇒ "ZIP" package (e.g., "apache-tomcat-8.0.{xx}.zip
", about 8 MB). - Create your project directory, say "
d:\myProject
" or "c:\myProject
". UNZIP the downloaded file into your project directory. Tomcat will be unzipped into directory "d:\myProject\apache-tomcat-8.0.{xx}
". - For ease of use, we shall shorten and rename this directory to "
d:\myProject\tomcat
".
Take note of Your Tomcat Installed Directory. Hereafter, I shall refer to the Tomcat installed directory as <TOMCAT_HOME>
.
For Mac OS X
- Goto http://tomcat.apache.org ⇒ Download ⇒ Tomcat 8.0 ⇒ "
8.0.{xx}
" (where{xx}
denotes the latest upgrade number) ⇒ Binary distribution ⇒ Core ⇒ "tar.gz" package (e.g., "apache-tomcat-8.0.{xx}.tar.gz
", about 8 MB). - To install Tomcat:
- Goto "
~/Downloads
", double-click the downloaded tarball (e.g., "apache-tomcat-8.0.{xx}.tar.gz
") to expand it into a folder (e.g., "apache-tomcat-8.0.{xx}
"). - Move the extracted folder (e.g., "
apache-tomcat-8.0.{xx}
") to "/Applications
". - For ease of use, we shall shorten and rename this folder to "tomcat".
- Goto "
Take note of Your Tomcat Installed Directory. Hereafter, I shall refer to the Tomcat installed directory as <TOMCAT_HOME>
.
For Ubuntu
Read "How to Install Tomcat 8 on Ubuntu". You need to switch between these two articles.
For academic learning, I recommend "zip
" (or "tar.gz
") version, as you could simply delete the entire directory when Tomcat is no longer needed (without running any un-installer). You are free to move or rename the Tomcat's installed directory. You can install (unzip) multiple copies of Tomcat in the same machine. For production, it is easier to use the installer to properly configure the Tomcat.
Tomcat's Directories
Take a quick look at the Tomcat installed directory. It contains the following sub-directories:
- bin: contains the binaries; and startup script (
startup.bat
for Windows andstartup.sh
for Unixes and Mac OS X), shutdown script (shutdown.bat
for Windows andshutdown.sh
for Unix and Mac OS X), and other binaries and scripts. - conf: contains the system-wide configuration files, such as
server.xml
,web.xml
,context.xml
, andtomcat-users.xml
. - lib: contains the Tomcat's system-wide JAR files, accessible by all webapps. You could also place external JAR file (such as MySQL JDBC Driver) here.
- logs: contains Tomcat's log files. You may need to check for error messages here.
- webapps: contains the webapps to be deployed. You can also place the WAR (Webapp Archive) file for deployment here.
- work: Tomcat's working directory used by JSP, for JSP-to-Servlet conversion.
- temp: Temporary files.
STEP 2: Create an Environment Variable JAVA_HOME
(For Windows)
You need to create an environment variable called "JAVA_HOME
" and set it to your JDK installed directory.
- First, find your JDK installed directory. The default is "
c:\Program Files\Java\jdk1.8.0_{xx}
", where{xx}
is the upgrade number. Take note of your JDK installed directory. - To set the environment variable
JAVA_HOME
in Windows 7/8/10: Start "Control Panel" ⇒ System ⇒ Advanced system settings ⇒ Switch to "Advanced" tab ⇒ Environment Variables ⇒ System Variables ⇒ "New" ⇒ In "Variable Name", enter "JAVA_HOME
" ⇒ In "Variable Value", enter your JDK installed directory as noted in Step 1. - To verify, RE-START a CMD shell (restart needed to refresh the environment) and issue:
SET JAVA_HOME JAVA_HOME=c:\Program Files\Java\jdk1.8.0_{xx} <== Verify that this is YOUR JDK installed directory
(For Mac OS X)
Skip this step. No need to do anything.
STEP 3: Configure Tomcat Server
The Tomcat configuration files are located in the "conf
" sub-directory of your Tomcat installed directory, e.g. "d:\myProject\tomcat\conf
" (for Windows) or "/Applications/tomcat/conf
" (for Mac OS X). There are 4 configuration XML files:
server.xml
web.xml
context.xml
tomcat-users.xml
Make a BACKUP of the configuration files before you proceed.
Step 3(a) "conf\server.xml" - Set the TCP Port Number
Use a programming text editor (e.g., NotePad++, TextPad for Windows; or gEdit, jEdit for Mac OS X) to open the configuration file "server.xml
", under the "conf
" sub-directory of Tomcat installed directory.
The default TCP port number configured in Tomcat is 8080, you may choose any number between 1024 and 65535, which is not used by an existing application. We shall choose 9999 in this article. (For production server, you should use port 80, which is pre-assigned to HTTP server as the default port number.)
Locate the following lines (around Line 69) that define the HTTP connector, and change port="8080"
to port="9999"
.
 <Connector port="9999" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
Step 3(b) "conf\web.xml" - Enabling Directory Listing
Again, use a programming text editor to open the configuration file "web.xml
", under the "conf
" sub-directory of Tomcat installed directory.
We shall enable directory listing by changing "listings
" from "false
" to "true
" for the "default
" servlet. This is handy for test system, but not for production system for security reasons.
Locate the following lines (around Line 103) that define the "default" servlet; and change the "listings" from "false
" to "true
".
   <servlet> <servlet-name>default</servlet-name> <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class> <init-param> <param-name>debug</param-name> <param-value>0</param-value> </init-param> <init-param> <param-name>listings</param-name> <param-value>true</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet>
Step 3(c) "conf\context.xml" - Enabling Automatic Reload
We shall add the attribute reloadable="true"
to the <Context>
element to enable automatic reload after code changes. Again, this is handy for test system but not for production, due to the overhead of detecting changes.
Locate the <Context>
start element (around Line 19), and change it to <Context reloadable="true">
.
<Context reloadable="true">
......
......
</Context>
Step 3(d) (Optional) "conf\tomcat-users.xml"
Enable the Tomcat's manager by adding the highlighted lines, inside the <tomcat-users>
elements:
<tomcat-users> <role rolename="manager-gui"/> <user username="manager" password="xxxx" roles="manager-gui"/> </tomcat-users>
This enables the manager GUI app for managing Tomcat server.
STEP 4: Start Tomcat Server
The Tomcat's executable programs and scripts are kept in the "bin
" sub-directory of the Tomcat installed directory, e.g., "d:\myProject\tomcat\bin
" (for Windows) or "/Applications/tomcat/bin
" (for Mac OS X).
Step 4(a) Start Server
For Windows
Launch a CMD shell. Set the current directory to "<TOMCAT_HOME
>\bin
", and run "startup.bat
" as follows:
// Change the current directory to Tomcat's "bin" // Assume that Tomcat is installed in "d:\myProject\tomcat" d: // Change the current drive cd \myProject\tomcat\bin // Change Directory to YOUR Tomcat's "bin" directory // Start Tomcat Server startup
For Mac OS X
I assume that Tomcat is installed in "/Applications/tomcat
". To start the Tomcat server, open a new "Terminal" and issue:
// Change current directory to Tomcat's binary directory cd /Applications/tomcat/bin // Start tomcat server ./catalina.sh run
A new Tomcat console window appears. Study the messages on the console. Look out for the Tomcat's port number (double check that Tomcat is running on port 9999). Future error messages will be send to this console. System.out.println()
issued by your Java servlets will also be sent to this console.
...... ...... xxx xx, xxxx x:xx:xx xx org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["http-bio-9999"] xxx xx, xxxx x:xx:xx xx org.apache.coyote.AbstractProtocol start INFO: Starting ProtocolHandler ["ajp-bio-8009"] xxx xx, xxxx x:xx:xx xx org.apache.catalina.startup.Catalina start INFO: Server startup in 2477 ms
(Skip Unless ...) Cannot Start Tomcat: Read "How to Debug".
Step 4(b) Start a Client to Access the Server
Start a browser (as HTTP client). Issue URL "http://localhost:9999
" to access the Tomcat server's welcome page. The hostname "localhost
" (with IP address of <IP_ADDRESS>
) is meant for local loop-back testing inside the same machine. For users on the other machines over the net, they have to use the server's IP address or DNS domain name or hostname in the format of "http://serverHostnameOrIPAddress:9999
".
Try issuing URL http://localhost:9999/examples
to view the servlet and JSP examples. Try running some of the servlet examples.
(Optional) Try issuing URL http://localhost:9999/manager/html
to run the Tomcat Web Manager. Enter the username and password configured earlier in tomcat-users.xml
.
Step 4(c) Shutdown Server
For Windows
You can shutdown the tomcat server by either:
- Press Ctrl-C on the Tomcat console; OR
- Run "
<TOMCAT_HOME>\bin\shutdown.bat
" script. Open a new "cmd" and issue:// Change the current directory to Tomcat's "bin" d: // Change the current drive cd \myProject\tomcat\bin // Change Directory to YOUR Tomcat's "bin" directory // Shutdown the server shutdown
For Mac OS X
To shutdown the Tomcat server:
- Press Control-C (NOT Command-C) on the Tomcat console; OR
- Run the "
<TOMCAT_HOME>/bin/shutdown.sh
" script. Open a new "Terminal" and issue:// Change current directory to Tomcat's bin directory cd /Applications/tomcat/bin // Shutdown the server ./shutdown.sh
WARNING: You MUST properly shutdown the Tomcat. DO NOT kill the cat by pushing the window's "CLOSE" button.
STEP 5: Develop and Deploy a WebApp
Step 5(a) Create the Directory Structure for your WebApp
First of all, choose a name for your webapp. Let's call it "hello
". Goto Tomcat's "webapps
" sub-directory. Create the following directory structure for you webapp "hello
" (as illustrated):
- Under Tomcat's "
webapps
", create your webapp root directory "hello
" (i.e., "<TOMCAT_HOME>\webapps\hello
"). - Under "
hello
", create a sub-directory "WEB-INF
" (case sensitive, a "dash" not an underscore) (i.e., "<TOMCAT_HOME>\webapps\hello\WEB-INF
"). - Under "
WEB-INF
", create a sub-sub-directory "classes
" (case sensitive, plural) (i.e., "<TOMCAT_HOME>\webapps\hello\WEB-INF\classes
").
You need to keep your web resources (e.g., HTMLs, CSSs, images, scripts, servlets, JSPs) in the proper directories:
- "
hello
": The is called the context root (or document base directory) of your webapp. You should keep all your HTML files and resources visible to the web users (e.g., HTMLs, CSSs, images, scripts, JSPs) under this context root. - "
hello/WEB-INF
": This directory, although under the context root, is not visible to the web users. This is where you keep your application's web descriptor file "web.xml
". - "
hello/WEB-INF/classes
": This is where you keep all the Java classes such as servlet class-files.
You should RE-START your Tomcat server to pick up the hello
webapp. Check the Tomcat's console to confirm that "hello
" application has been properly depolyed:
......
INFO: Deploying web application directory D:\myProject\tomcat\webapps\hello
......
You can issue the following URL to access the web application "hello
":
http://localhost:9999/hello
You should see the directory listing of the directory "<TOMCAT_HOME>\webapps\hello
", which shall be empty (provided you have enabled directory listing in web.xml
earlier).
Step 5(b) Write a Welcome Page
Create the following HTML page and save as "HelloHome.html
"
in your application's root directory "hello
".
1 2 3 4 5 6 |
 <title>My Home Page</title>
My Name is so and so. This is my HOME.
   |
You can browse this page by issuing this URL:
http://localhost:9999/hello/HelloHome.html
Alternatively, you can issue an URL to your web application root "hello
":
http://localhost:9999/hello
The server will return the directory listing of your base directory. You can then click on "HelloHome.html
".
Rename "HelloHome.html
" to "index.html
", and issue a directory request again:
http://localhost:9999/hello
Now, the server will redirect the directory request to "index.html
", if the root directory contains an "index.html
", instead of serving the directory listing.
You can check out the home page of your peers by issuing:
http://YourPeerHostnameOrIPAddress:9999/hello http://YourPeerHostnameOrIPAddress:9999/hello/HelloHome.html http://YourPeerHostnameOrIPAddress:9999/hello/index.html
with a valid "YourPeerHostnameOrIPAddress
", provided that your peer has started his tomcat server and his firewall does not block your access. You can use command such as "ipconfig
" (Windows), "ifconfig
" (Mac OS X and Unix) to find your IP address.
(Skip Unless...) The likely errors are "Unable to Connect", "Internet Explorer cannot display the web page", and "404 File Not Found". Read "How to Debug" section.
STEP 6: Write a "Hello-world" Java Servlet
A servlet is Java program that runs inside a Java-capable HTTP Server, such as Apache Tomcat. A web user invokes a servlet by issuing an appropriate URL from a web browser (HTTP client).
Before you proceed, I shall assume that you are familiar with Java Programming and have installed the followings:
- JDK (Read "How to install JDK and Get Started").
- A programming text editor, such as TextPad or Notepad++ (for Windows); jEdit or gEdit (for Mac OS X) (Read "Programming Text Editor").
Step 6(a) Write a "Hello-world" Java Servlet
A Java servlet is a Java program that runs inside a HTTP server. A web user invokes a servlet by issuing a URL from a browser (or HTTP client).
In this example, we are going to write a Java servlet called HelloServlet
, which says "Hello, world!". We will then write a configuration such that web users can invoke this servlet by issuing URL http://hostname:port/hello/sayhello
from their browser, as illustrated:
Write the following source codes called "HelloServlet.java
" and save it under your application "classes
" directory (i.e., "<TOMCAT_HOME>\webapps\hello\WEB-INF\classes\HelloServlet.java
"). This servlet says "Hello", echos some request information, and prints a random number upon each request.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
// To save as "<TOMCAT_HOME>\webapps\hello\WEB-INF\classes\HelloServlet.java" import java.io.*; import javax.servlet.*; import javax.servlet.http.*; public class HelloServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Set the response MIME type of the response message response.setContentType("text/html"); // Allocate a output writer to write the response message into the network socket PrintWriter out = response.getWriter(); // Write the response message, in an HTML page try { out.println(""); out.println("<title>Hello, World</title>"); out.println(""); out.println("
Hello, world!
"); // says Hello // Echo client's request information out.println("
Request URI: " + request.getRequestURI() + "
"); out.println("
Protocol: " + request.getProtocol() + "
"); out.println("
PathInfo: " + request.getPathInfo() + "
"); out.println("
Remote Address: " + request.getRemoteAddr() + "
"); // Generate a random number upon each request out.println("
A Random Number: " + Math.random() + "
"); out.println(""); } finally { out.close(); // Always close the output writer } } } |
Step 6(b) Compiling the Servlet
We need the Servlet API to compile the servlet. Servlet API is NOT part of JDK. Nonetheless, Tomcat provides a copy in <TOMCAT_HOME>/lib/servlet-api.jar
. We need to include this JAR file in the compilation via the -cp
(classpath) option.
(For Windows)
// Assume that Tomcat is installed in d:\myProject\tomcat // Change directory to the source file d: cd \myProject\tomcat\webapps\hello\WEB-INF\classes // Compile javac -cp .;d:\myProject\tomcat\lib\servlet-api.jar HelloServlet.java // Note: You need to enclose the jar file in double quotes if the path contains blank // e.g., javac -cp .;"d:\Path To\tomcat\lib\servlet-api.jar" HelloServlet.java
(For Mac OS X)
// Assume that Tomcat is installed in /Applications/tomcat // Change directory to the source file cd /Applications/tomcat/webapps/hello/WEB-INF/classes // Compile javac -cp .:/Applications/tomcat/lib/servlet-api.jar HelloServlet.java
The output of the compilation is "HelloServlet.class
". Browse the "classes
" folder to make sure that it is created.
(Skip Unless...) Read "Common Errors in Compiling Java Servlet".
Step 6(c) Configure Servlet's Request URL in "webapps\hello\WEB-INF\web.xml"
A web user invokes a servlet, which is kept in the web server, by issuing a request URL from the browser. We need to configure this request URL for our HelloServlet
.
Create the following configuration file called "web.xml
", and save it under "webapps\hello\WEB-INF
" (i.e., "<TOMCAT_HOME>\webapps\hello\WEB-INF\web.xml
").
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">  <servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>HelloServlet</servlet-class> </servlet>  <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/sayhello</url-pattern> </servlet-mapping> </web-app> |
In the above configuration, a servlet having a class file "HelloServlet.class
" is mapped to request URL "/sayhello
" (via an arbitrary servlet-name
"HelloWorld
"), under this web application "hello
". In other words, the complete request URL for this servlet is "http://hostname:port/hello/sayhello
".
This configuration file, saved under your webapp "hello
", is applicable only to this particular webapp "hello
".
RESTART your Tomcat server to refresh the "web.xml
" file.
IMPORTANT: For EACH servlet, you need to write a pair of <servlet>
and <servlet-mapping>
elements with a common but arbitrary <servlet-name>
. Take note that all the <servlet>
elements MUST be grouped together and placed IN FRONT of the <servlet-mapping>
elements.
Step 6(d) Invoke the Servlet
To run this servlet, start a browser, and issue the request URL configured earlier:
http://localhost:9999/hello/sayhello
You shall see the output of the servlet displayed in your web browser.
Refresh the browser, you shall see a new random number upon each refresh. In other word, the doGet()
method of the servlet runs once per request.
Try "View Source" to look at the output received by the web users. Take note that the web users receive only the output of the servlet (generated via the out.println()
statements). They have no access to the servlet programs (which may contain confidential information).
(For Mac OS X's Safari browser) You need to enable "Developer Menu" under the "Preferences" to enable the "View Source" menu.
 <title>Hello, World</title>
Hello, world!

Request URI: /hello/sayhello

Protocol: HTTP/1.1

PathInfo: null

Remote Address: <IP_ADDRESS>

A Random Number: 0.3523682325749493

(Skip Unless...) The likely errors are "404 File Not Found" and "500 Internal Server Error". Read "How to debug" Section.
STEP 7: Write a Database Servlet
This section assumes that you are familiar with "Java database programming" and "MySQL database server". Otherwise, read "Java Database Program" and "How to Install MySQL 5 and Get Started".
Step 7(a) Setup a Database on MySQL
Start your MySQL server. Take note of the server's port number. I shall assume that the MySQL server is running on port 3306
(whereas the Tomcat is running on port 9999
).
// For Windows cd {path-to-mysql-bin} // Check your MySQL installed directory mysqld --console // For Mac OS X // Use graphical control at "System Preferences" -> MySQL
Start a MySQL client. I shall assume that there is a user called "myuser
" with password "xxxx
".
// For Windows cd {path-to-mysql-bin} // Check your MySQL installed directory mysql -u myuser -p // For Mac OS X cd /usr/local/mysql/bin ./mysql -u myuser -p
Run the following SQL statements to create a database called "ebookshop
", with a table called "books
" with 5 columns: id
, title
, author
, price
, qty
.
create database if not exists ebookshop; use ebookshop; drop table if exists books; create table books ( id int, title varchar(50), author varchar(50), price float, qty int, primary key (id)); insert into books values (1001, 'Java for dummies', 'Tan Ah Teck', 11.11, 11); insert into books values (1002, 'More Java for dummies', 'Tan Ah Teck', 22.22, 22); insert into books values (1003, 'More Java for more dummies', 'Mohammad Ali', 33.33, 33); insert into books values (1004, 'A Cup of Java', 'Kumar', 55.55, 55); insert into books values (1005, 'A Teaspoon of Java', 'Kevin Jones', 66.66, 66); select * from books;
Step 7(b) Install MySQL JDBC Driver
You need to download MySQL JDBC driver if you have not done so. Read "Installing the MySQL JDBC Driver".
(For Advanced Users Only) You could also place the MySQL driver jar-file "mysql-connector-java-5.1.{xx}-bin.jar
" in Tomcat's "lib
" directory.
Step 7(c) Write a Client-side HTML Form
Let's write an HTML script to create a query form with 3 checkboxes and a submit button, as illustrated below. Save the HTML file as “querybook.html
” in your application root directory “<TOMCAT_HOME>\webapps\hello
”.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
  <title>Yet Another Bookshop</title>
Yet Another Bookshop
 <form method="get" action="http://localhost:9999/hello/query"> Choose an author: <input type="checkbox" name="author" value="Tan Ah Teck">Ah Teck <input type="checkbox" name="author" value="Mohammad Ali">Ali <input type="checkbox" name="author" value="Kumar">Kumar <input type="submit" value="Search"> </form>   |
You can browse the HTML page by issuing the following URL:
http://localhost:9999/hello/querybook.html
Check a box (e.g., "Tan Ah Teck") and click the "Search" button. An HTTP GET request will be issued to the URL specified in the <form>
's "action
" attribute. Observe the URL of the HTTP GET request:
http://localhost:9999/hello/query?author=Tan+Ah+Teck
The request consists of two part: a URL corresponding to the "action
" attribute of the <form>
tag, and the "name=value" pair extracted from the <input>
tag, separated by a '?'
. Take note that blanks are replaced by '+'
(or %20
), because blanks are not allowed in the URL.
If you check two boxes (e.g., "Tan Ah Teck" and "Mohammad Ali"), you will get this URL, which has two "name=value" pairs separated by an '&'
.
http://localhost:9999/hello/query?author=Tan+Ah+Teck&author=Mohammad+Ali
You are expected to get an error "404 File Not Found", as you have yet to write the server-side program.
Step 7(d) Write the Server-side Database Query Servlet
The next step is to write a Java servlet, which responses to the client’s request by querying the database and returns the query results.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 |
// To save as "<TOMCAT_HOME>\webapps\hello\WEB-INF\classes\QueryServlet.java". import java.io.*; import java.sql.*; import javax.servlet.*; import javax.servlet.http.*; public class QueryServlet extends HttpServlet { // JDK 6 and above only // The doGet() runs once per HTTP GET request to this servlet. @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { // Set the MIME type for the response message response.setContentType("text/html"); // Get a output writer to write the response message into the network socket PrintWriter out = response.getWriter(); Connection conn = null; Statement stmt = null; try { // Step 1: Allocate a database Connection object conn = DriverManager.getConnection( "jdbc:mysql://localhost:3306/ebookshop?useSSL=false", "myuser", "xxxx"); // <== Check! // database-URL(hostname, port, default database), username, password // Step 2: Allocate a Statement object within the Connection stmt = conn.createStatement(); // Step 3: Execute a SQL SELECT query String sqlStr = "select * from books where author = " + "'" + request.getParameter("author") + "'" + " and qty > 0 order by price desc"; // Print an HTML page as the output of the query out.println("<title>Query Response</title>"); out.println("
Thank you for your query.
"); out.println("
You query is: " + sqlStr + "
"); // Echo for debugging ResultSet rset = stmt.executeQuery(sqlStr); // Send the query to the server // Step 4: Process the query result set int count = 0; while(rset.next()) { // Print a paragraph
...
 for each record out.println("
" + rset.getString("author") + ", " + rset.getString("title") + ", $" + rset.getDouble("price") + "
"); count++; } out.println("
==== " + count + " records found =====
"); out.println(""); } catch (SQLException ex) { ex.printStackTrace(); } finally { out.close(); // Close the output writer try { // Step 5: Close the resources if (stmt != null) stmt.close(); if (conn != null) conn.close(); } catch (SQLException ex) { ex.printStackTrace(); } } } } |
Compile the source "QueryServlet.java
" into "QueryServlet.class
". See the previous example in Step 6(b) on how to compile a servlet.
Step 7(e) Configure the Request URL for the Servlet
Open the configuration file "web.xml
" of your application "hello
" that you have created earlier for the HelloServlet
, i.e., "<TOMCAT_HOME>\webapps\hello\WEB-INF\web.xml
". Add the lines that are shown in red at the LOCATIONS INDICATED.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
<?xml version="1.0" encoding="ISO-8859-1"?> <web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">  <servlet> <servlet-name>HelloWorld</servlet-name> <servlet-class>HelloServlet</servlet-class> </servlet> <servlet> <servlet-name>UserQuery</servlet-name> <servlet-class>QueryServlet</servlet-class> </servlet>  <servlet-mapping> <servlet-name>HelloWorld</servlet-name> <url-pattern>/sayhello</url-pattern> </servlet-mapping> <servlet-mapping> <servlet-name>UserQuery</servlet-name> <url-pattern>/query</url-pattern> </servlet-mapping> </web-app> |
The above lines configure the following URL to invoke QueryServlet
:
http://localhost:9999/hello/query
Step 7(f) Invoke the Servlet from the Client-Side Form
Issue the following URL to browse the HMTL form "querybook.html
" that you have created earlier:
http://localhost:9999/hello/querybook.html
Select an author (e.g., "Tan Ah Teck") and click the submit button, which activates the following URL coded in the <form>
's "action
" attribute, together with the name=value pair:
http://localhost:9999/hello/query?author=Tan+Ah+Teck
This URL "/query
" triggers QueryServlet
. The QueryServlet
retrieves the name=value pair of "author=Tan+Ah+Teck
". Inside the QueryServlet
, the method request.getParameter("author")
returns "Tan Ah Teck
", which is inserted into the SQL SELECT
command to query the database. The processed query result is then written to the client as an HTML document.
(Skip Unless...) The likely errors are "404 File Not Found" and "500 Internal Server Error". Read "How to debug" Section.
(Advanced) Deploying Servlet using @WebServlet (Servlet 3.0 on Tomcat 7)
Servlet 3.0, which is supported by Tomcat 7, introduces the @WebServlet
annotation, which greatly simplifies the deployment of servlets. You no longer need to write the deployment descriptor in "web.xml
". Instead, you can use the @WebServlet
annotation to specify the url mapping.
For example, let us write a new servlet called AnotherHelloServlet.java
, by modifying the HelloServlet.java
written earlier, with url mapping of "sayhi
".
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 |
// To save as "<TOMCAT_HOME>\webapps\hello\WEB-INF\classes\AnotherHelloServlet.java" import java.io.*; import javax.servlet.*; import javax.servlet.http.*; import javax.servlet.annotation.*; @WebServlet("/sayhi") public class AnotherHelloServlet extends HttpServlet { @Override public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { // Set the response MIME type response.setContentType("text/html;charset=UTF-8"); // Allocate a output writer to write the response message into the network socket PrintWriter out = response.getWriter(); // Write the response message, in an HTML page try { out.println(""); out.println("<title>Hello, World</title>"); out.println(""); out.println("
Hello world, again!
"); // says Hello // Echo client's request information out.println("
Request URI: " + request.getRequestURI() + "
"); out.println("
Protocol: " + request.getProtocol() + "
"); out.println("
PathInfo: " + request.getPathInfo() + "
"); out.println("
Remote Address: " + request.getRemoteAddr() + "
"); // Generate a random number upon each request out.println("
A Random Number: " + Math.random() + "
"); out.println(""); } finally { out.close(); // Always close the output writer } } } |
In Line 7, the annotation @WebServlet("/sayhi")
is used to declare the URL mapping for this servlet, i.e., http://localhost:9999/hello/sayhi
. There is no need to provide any more configuration in "web.xml
"!
How to Debug?
"Everything that can possibly go wrong will go wrong." The most important thing to do is to find the ERROR MESSAGE!!!
Always...
- Refresh your browser using Cntl-F5 (instead of refresh button or simply F5) to get a fresh copy, instead of from the cache.
- You may re-start your Tomcat server. You may also re-start your browser to clear the cache.
- Check your spelling! Always assume that all programs are case-sensitive. Don't type, copy and paste if possible!
- and MOST IMPORTANTLY - Find the ERROR MESSAGE!!!
- Check the Error Messages on Tomcat's Console. Most of the error messages have a few screens of lines. You need to scroll up slowly from the last line to look for the FIRST LINE of the error messages.
- Check the Tomcat's log files, located at "
<TOMCAT_HOME>\logs
". The "catalina.yyyy-mm-dd.log
" shows the Tomcat's startup messages. Also check the "localhost.yyyy-mm-dd.log
".
- If things were running fine until the lightning strikes, ask yourself "What have I changed?"
Cannot Start Tomcat - Tomcat's Console Flashes and Disappears
- Try running the script "
configtest.bat
" (for Windows) or "./configtest.sh
" (for Mac OS X/Linux) to check your configuration files. - Check the Tomcat's log files for error messages. The log files are located at "
<TOMCAT_HOME>\logs
". The "catalina.{yyyy-mm-dd}.log
" shows the Tomcat's startup messages. Also check the "localhost.{yyyy-mm-dd}.log
". - If the error messages indicate that another Tomcat instance is running (
java.net.BindException: Address already in use: JVM_Bind
), kill the Tomcat process (see below); or try running the "shutdown" script at Tomcat'sbin
(For Windows, simply double-click the "shutdown.bat
" or issue "shutdown
" from CMD. For Mac OS X, issue "./shutdown.sh
" from Terminal.) - If the error messages indicate that another application is running on the Tomcat's port numbers, then you need to change the Tomcat's port number in
server.xml
. You can issue command "netstat -an
" to check the status of all the ports. - Start the tomcat in the debugging mode by running "
catalina debug
" (or./catalina.sh debug
) and type "run
" in the "jdb
" prompt. Look for the error messages.
Locating/Killing Tomcat's Process
- In windows, start "Task Manager", Tomcat run as a "process" named "
java.exe
". You may need to kill the process. - In Mac OS X, start "Activity Monitor". Select "All Processes" and look for "
java.exe
". - In Linux/Mac OS X, you may issue "
ps aux | grep tomcat
" to locate the Tomcat process. Note down the process ID (pid). You can kill the Tomcat process via "kill -9 pid
".
(Firefox) Unable to Connect
(IE) Internet Explorer cannot display the webpage
(Chrome) Oops! Google Chrome could not connect to ...
(Safari) Safari can't connect to the server
Cause: You are simply not connecting to your Tomcat.
Solution:
- Check if your Tomcat server has been started?
- Check the hostname and port number, separated by a colon
':'
, of your URL (http://localhost:9999/...
).
Error 404 File Not Found
Cause: You have connected to your Tomcat. But Tomcat server cannot find the HTML file or Servlet that your requested.
Solution:
- Check your spelling! The path is case-sensitive!
- For HTML file with URL
http://localhost:9999/xxxx/filename.html
:- Open Tomcat's "
webapps
" directory, check if sub-directory "xxxx
" exists. It is case-sensitive. - Open the "
xxxx
" directory, check if "filename.html
" exists.
- Open Tomcat's "
- For Servlet with URL
http://localhost:9999/xxxx/servletURL
:- Check the Tomcat's console for error message. Your application cannot be deployed if you make a mistake in editing "
web.xml
", which triggered many error messages. - Check the Tomcat console to make sure that your application has been deployed.
- Open Tomcat's "
webapps
" directory, check if sub-directory "xxxx
" exists. - Open the "
xxxx
" directory, check if sub-sub-directory "WEB-INF
" (uppercase with a dash) exists. - Open the "
WEB-INF
", check if sub-sub-sub directory "classes" (lowercase, plural) exists. - Open the configuration file "
WEB-INF\web.xml
":- Check that
servletURL
is defined in a<servlet-mapping>
tag. Take note of thename
in<servlet-name>
tag. - Based on the
name
noted, look for the matching<servlet-class>
tag. Take note of theServletClassname
. - Open "
WEB-INF\classes
", check if "ServletClassname
.class
" that you noted exists (Note: It is ".class
", and NOT ".java
". You need to compile the ".java
" to get the ".class
".)
- Check that
- Check the Tomcat's console for error message. Your application cannot be deployed if you make a mistake in editing "
Error 500 Internal Server Error
Error 500 should have triggered many error message in the Tomcat's console. Go to the Tomcat's console, find the error message. The error message spans tens of lines. You need to scroll up slowly to look for the first line of the error message. The error message should tell you the cuase of this error, e.g. SQL syntax error, wrong user/password, etc.
For database servlet, you may check the error messages at "Common Errors in JDBC Programming".
- For "No suitable driver found" (Windows) or
NullPointerException
(Mac OS X and Linux): Read Step 7(b) again, again, and again.
More Errors
Try searching "Common Error Messages".
REFERENCES & RESOURCES
- Apache Tomcat mother site @ http://tomcat.apache.org.
- Apache Tomcat Documentation @ "
<TOMCAT_HOME>\webapps\docs
". - "How to install MySQL and Get Started".
- "Introduction to Java Database (JDBC) Programming".
- Jason Brittain, Ian F. Darwin, "Tomcat The Definitive Guide", 2nd eds, OReilly, 2007.


SERVAL 1.0.0
1. SERVAL summary
SERVAL is a monitoring/management software targets to servers and IoT devices.
Due to definition and execution of Windows batch files and Linux shell scripts from remote, flexible monitoring and management of servers and IoT devices can be provided.
SERVAL is constitute of SERVAL server which provides management console and SERVAL agents which are installed in servers/IoT devices.
SERVAL provides following features.
- Provides management console can be connected from Web browser.
- Maximum 90 servers and IoT devices can be managed.
- All of operations on management console can be performed by smartphone.
- A command is constitute of file transfer from SERVAL server to SERVAL agent, script execution and file transfer
from SERVAL agent to SERVAL server. Because of this, SERVAL can provide various monitoring/management operations.
- SERVAL provides periodical command execution feature aiming to monitoring and Immediate command execution feature aiming to management.
- Connection establishment between SERVAL server and SERVAL agent is always direction to SERVAL server from SERVAL agent.
No need to open receiver ports of servers and IoT devices hence, secure monitoring/management can be provided.
2. System requirements
SERVAL works on systems with the following specifications:
- Free disk space: 20 MB or more
- Operating systems supported:
SERVAL server
Windows 10
Windows 11
Windows Server 2016
Windows Server 2019
SERVAL agent
Windows 10
Windows 11
Windows Server 2016
Windows Server 2019
Redhat Enterprise Linux 8.x
AlmaLinux 8.x
-
Web browsers supported:
Microsoft Edge
Google Chrome
Mozilla Firefox
3. Package structure
SERVAL is provided as following two package structures.
- svl100.zip
SERVAL server for Windows edition and SERVAL agents for multi platform edition are included as .msi files and .rpm file.
- serval-1.0.0.msi : SERVAL server installation file for Windows edition
- servalagt-1.0.0.msi : SERVAL agent installation file for Windows edition
- servalagt-1.0-0.el8.x86_64.rpm : SERVAL agent installation file for Linux edition
- ReadmeENG.html : English readme file
- ReadmeJPN.html : Japanese readme file
- svl100.tar.gz
SERVAL server for Linux edition and SERVAL agents for multi platform edition are included as .msi file and .rpm files.
- serval-1.0-0.el8.x86_64.rpm : SERVAL server installation file for Linux edition
- servalagt-1.0.0.msi : SERVAL agent installation file for Windows edition
- servalagt-1.0-0.el8.x86_64.rpm : SERVAL agent installation file for Linux edition
- ReadmeENG.html : English readme file
- ReadmeJPN.html : Japanese readme file
4. SERVAL server
4.1 Installation
For Windows
Execute serval-1.0.0.msi and launch the installer of SERVAL server.
Follow the on-screen dialog prompts.
SERVAL server installer performs following steps during the installation.
- Register exceptions of Windows firewall for SERVAL server.
- Register service of SERVAL server to the target system.
- Auto start of SERVAL server service and Web server.
Overwrite installation(Repair) can be performed if serval-1.0.0.msi is executed after SERVAL server installation.
Note that the items shown below for overwrite installation.
- Stop SERVAL server service before overwrite installation. If you perform the overwrite installation without service stop, restart of operating system is required after overwrite installation done.
- During overwrite installation, host name/IP address and port number which Web server and SERVAL server service use might be changed into default. Confirm the port number after overwrite installation.
For Linux
Install serval-1.0-0.el8.x86_64.rpm using following command.
# yum install serval-1.0-0.el8.x86_64.rpm
Note that nginx 1.12.2-1(nginx-1.12.2-1.el7_4.ngx.x86_64.rpm) needs to be installed before SERVAL server installation.
SERVAL server installer performs following steps during the installation.
- Change httpd_can_network_connect of SELinux into on.
- Register exceptions of firewall for SERVAL server.
- Register service of SERVAL server to the target system.
- Auto start of SERVAL server service and restart of Web server.
4.2 Uninstallation
For Windows
Select Remove SERVAL with execution of serval-1.0.0.msi or perform uninstallation of SERVAL from Control Panel.
SERVAL server uninstallation performs following things during uninstallation.
- Auto stop of SERVAL server service and Web server.
- Deletion of SERVAL server service from the target system.
- Deletion of Windows firewall exception for SERVAL server.
For Linux
Uninstall SERVAL server using following command.
# yum remove serval
SERVAL server uninstallation performs following things during uninstallation.
- Auto stop of SERVAL server service and restart of Web server.
- Deletion of SERVAL server service from the target system.
- Deletion of firewall exception for SERVAL server.
4.3 Start/Stop SERVAL server service
For Windows
Start and stop of SERVAL server service can be performed by Windows start menu.
- [SERVAL]-[Start service] : Start service
- [SERVAL]-[Stop service] : Stop service
For Linux
Start and stop operation for SERVAL server can be performed by following command.
Start: # systemctl start serval
Stop: # systemctl stop serval
4.4 Properties of SERVAL server
You can configure SERVAL server setting by modification of serval.conf which is properties file of SERVAL server.
Properties file serval.conf is placed in <Installation folder> for Windows edition or in /etc directory for Linux edition.
- servicehost
Specify IP address or host name which the service uses. This value needs to be matched to proxy_pass directive in
<Installation folder>\conf\nginx.conf (for Windows edition) or /etc/nginx/conf.d/serval_nginx.conf (for Linux edition).
This IP address or host name is REST API service's one. REST API works as back-end of SERVAL server.
Endpoint IP address or host name which is specified by a browser needs to be conformed to server_name directive of nginx.conf or serval_nginx.conf.
- serviceport
Specify port number which the service uses. This value needs to be matched to proxy_pass directive of nginx.conf or serval_nginx.conf.
This port number is REST API service's one. REST API works as back-end of SERVAL server.
Endpoint port number which is specified by a browser needs to be conformed to listen directive of nginx.conf or serval_nginx.conf.
- workdir
Specify folder path of files which SERVAL server manages. The files can be referred by commands defined in SERVAL server.
SERVAL server service needs to be restarted after properties change in order to reflect the modified value.
5. SERVAL agent
5.1 Installation
For Windows
Execute servalagt-1.0.0.msi and launch the installer of SERVAL agent.
Follow the on-screen dialog prompts.
SERVAL agent installer registers SERVAL agent service to the target system.
Overwrite installation(Repair) can be performed if servalagt-1.0.0.msi is executed after SERVAL agent installation.
Note that the items shown below for overwrite installation.
- Stop SERVAL agent service before overwrite installation. If you perform the overwrite installation without service stop, restart of operating system is required after overwrite installation done.
- During overwrite installation, connection target host name/IP address and port number which SERVAL agent service uses might be changed into default. Confirm the port number after overwrite installation.
For Linux
Install servalagt-1.0-0.el8.x86_64.rpm using following command.
Installer changes httpd_can_network_connect of SELinux into on.
# yum install servalagt-1.0-0.el8.x86_64.rpm
5.2 Uninstallation
For Windows
Select Remove SERVAL agent with execution of servalagt-1.0.0.msi or perform uninstallation of SERVAL agent from Control Panel.
During uninstallation, SERVAL agent service is removed from the target system.
For Linux
Uninstall SERVAL agent using following command.
# yum remove servalagt
5.3 Start/Stop SERVAL agent service
For Windows
SERVAL agent service start and end operations can be performed by task manager.
Launch the task manager, and then perform start or stop operation to SERVALagent using the task manager.
For Linux
Start and stop operation for SERVAL agent can be performed by following command.
Start: # systemctl start servalagt
Stop: # systemctl stop servalagt
5.4 Properties of SERVAL agent
You can configure SERVAL agent setting by modification of servalagt.conf which is properties file of SERVAL agent.
Properties file servalagt.conf is placed in <Installation folder> for Windows edition or in /etc directory for Linux edition.
- targethost
Specify destination Web server IP address or host name. Do NOT specify REST API service's one.
- targetport
Specify destination Web server port number. Do NOT specify REST API service's one.
- hostname
Specify name of agent which will be registered into SERVAL server. Redundant names with other agents need to be avoided.
- workdir
Specify directory path of files which are used by commands in SERVAL agent.
- scriptencode
Specify encode type of command or command execution result. SJIS or UTF8 can be specified.
- securemode
Specify enablement or disablement of secure connection (TLS). true : enable, false : disable(default)
- trustedcert
Path to certificate file (.cer) of server.
SERVAL agent service needs to be restarted after properties change in order to reflect the modified value.
6. Login to SERVAL
Connect to the URL shown below by Web browser for use of SERVAL after installation. If main console is displayed after login sequence of SERVAL, it shows the installation is successfully completed.
http://<Host name or IP address of SERVAL server >:<Port number of Web server>
In case of specification of default installations parameters : http://localhost:8080
Initial login user name and password are follows.
User name : admin
Password : manager
If main console is not appeared or an error ocurred, confirm the things shown below.
- In case host name is specified in the URL for the connection to SERVAL from browser, confirm that the host name can be solved. If the host name is not solved, change the host name to other name which can be solved, and then retry.
- Confirm that SERVAL server (nginx.exe) is registered as an exception of firewall. If not, register nginx.exe to the firewall as an exception.
- Confirm that the specified port number is not duplicated from port numbers which other processes use. If duplicated, specify the independent port number according to the description shown later.
7. Change IP address/host name and port number
SERVAL server uses two kinds of IP addresses/host names and ports.
- IP address/host name and port of Web server
- IP address/host name and port of REST API service
In order to change the IP address/host name and port number after installation, following steps are required.
- Stop SERVAL server service.
-
Change IP address/host name and port number.
In case you change IP address/host name and port number which REST API service uses:
Specify IP address/host name and port number to servicehost and serviceport properties in <Installation folder>\serval.conf (for Windows)
or /etc/serval.conf (for Linux)
Specify IP address/host name and port number to proxy_pass of location /api/ section in <Installation folder>\conf\nginx.conf (for Windows)
or /etc/nginx/conf.d/serval_nginx.conf (for Linux)
In case you change IP address/host name and port number which Web server uses:
Change listen and server_name in <Installation folder>\conf\nginx.conf (for Windows) or /etc/nginx/conf.d/serval_nginx.conf (for Linux)
- Change firewall setting if necessary. If SELinux is enabled, add access permission to the target port using "semanage port" command.
- Start SERVAL server service.
- In case you change IP address/host name and port number which Web server uses, change destination IP address/host name and port number of SERVAL agent.
After you change targethost and targetport in SERVAL agent properties file "servalagt.conf", restart SERVAL agent.
8. Secure connection using TLS
In order to connect to SERVAL using TLS from browser, following steps are required.
- Stop SERVAL server service.
-
Add TLS settings to nginx.conf.
Add followings to server directive in <Installation folder>\conf\nginx.conf (for Windows) or /etc/nginx/conf.d/serval_nginx.conf (for Linux)
(Regarding certificate and private key, modify the path according to your environment.)
ssl on;
ssl_certificate "D:\\work\\server.crt";
ssl_certificate_key "D:\\work\\server.key";
- Change listen port number into 443 or appropriate HTTPS port number.
- Start SERVAL server service.
- Configure for secure connection of SERVAL agent. securemode and trustedcert in properties file servalagt.conf of SERVAL agent need to be configured.
- Restart SERVAL agent service.
9. Contact
Please use the E-mail address below for inquiries about this product.
<EMAIL_ADDRESS>https://github.com/s-takeuchi
Shinya Takeuchi


{{.FeedbackButton}}
Rotations you own or are a member of
{{if not .Rotas}}
Not a member or owner of any rotations
{{end}} {{with .Rotas}}
{{range $c := .}}
{{$c}}
{{end}}
{{end}}


- Description
- extends an existing XDispatch implementation with functionality
for dispatch recording
This interface can be implemented as an additional one beside an existing
XDispatch one to provide record functionality of dispatches.
Because it's an additional interface the status events are available there
and not at this interface.
But normaly this interface mustn't be used directly.
If a dispatch object is well known and recording was enabled
on a XDispatchRecorderSupplier it's possible to use method
XDispatchRecorderSupplier::dispatchAndRecord() of it
to make dispatch and recording automaticly. The interface XRecordableDispatch
is used transparently there.
- Example
XDispatch xDispatcher = xFrame.queryDispatch(aURL,"",0);
XRecordableDispatch xRecordable = (XRecordableDispatch)UnoRuntime.queryInterface(
XRecordableDispatch.class,
xDispatcher);
xDispatcher.addStatusListener(this,aURL);
if (xRecordable!=null)
xRecordable.dispatchAndRecord(aURL,lArguments,xRecorder);
else
xDispatcher.dispatch(aURL,lArguments);
...
xDispatcher.removeStatusListener(this,aURL);
- Since
- OOo 1.1.2
- See also
- XDispatchRecorderSupplier, XDispatch
|


{% extends "base.html" %} {% load static %} {% block title %} {{ title }} {% endblock title %} {% block content %}
“Sometimes, you read a book and it fills you with this weird evangelical zeal, and you become convinced that the shattered world will never be put back together unless and until all living humans read the book.”
― John Green
“Sometimes, you read a book and it fills you with this weird evangelical zeal, and you become convinced that the shattered world will never be put back together unless and until all living humans read the book.”
― John Green


--- title: "Contact" draft: false ---
Division of Psychology School of Social Sciences Nanyang Technological University 14 Nanyang Drive Singapore 637332
<EMAIL_ADDRESS>Facebook
Twitter
Github
Find out more about the Division of Psychology at Nayang Technological University (NTU)


Demetra Demetracopoulos
Front-End Developer
Featured Work
Mockup to Article
View on Github
Favorite Animal
View on Github
Pixel Art Maker
View on Github


{% extends "settings/base.html" %} {% block title %}Delete {{ domain.domain }} - Admin{% endblock %} {% block content %}
You cannot delete this domain as it has {{ num_identities }} identit{{ num_identities|pluralize:"y,ies" }} registered on it.
You will need to manually remove all identities from this domain in order to delete it.
Please confirm deletion of this domain - there are no identities registered on it.


Sexual Harassment
Logout
About
Terms & Condition
Privacy Policy
Account Info
Recent Tasks
Recent Posts
Forum
AI Legal Assistant
Logout Account
Account Information
Profile
Recent Tasks
{{ x.date}}
Recent Posts
{{ x.date }}
Forum
Create new post
Post Now
Discard
Legal Assistant
Comments
Username
Date
Contents
Forums
Account
About
Terms & Condition
Privacy Policy
Home
Office Location
Contact Us


DARK
ABOUT US
When you work with us, you are part of a team of commited collaborators. All aspects of our software development process are intergrated , interactive and agile.
Our approach unifies design, development and product managent to create exceptional products.
We start each project by understanding your business goals, the users needs and the product requirements.
we help translate them into active and elegant solutions.
SERVICES
Before we sign a contract or write a line of code, our team will spend the neccessary time needed to understand your product vission.
The outcome of the scoping session a proposal or high-level statement of work.
based on your requirements, we can provide a complete offering or just the piece you need.
WHAT WE DO
DESIGN
Our design practice offers a full range of services including brand strategy, interaction and visual design and user experience testing.
Throughout your project, our designers create and implement visual design and workflows, solicit user feedback and work with you to make sure what gets built is what is needed.
DESIGN
DEVELOPMENT
All engineers are fluent in the latest enterprise, mobile and web development technologies.
They collaborate with your team to write, and improve code on a daily basis, using proven practices such as test-driven development and pair programming.
DEVELOPMENT
PRODUCT MANAGEMENT
All engineers are fluent in the latest enterprise, mobile and web development technologies.
They collaborate with your team to write, and improve code on a daily basis, using proven practices such as test-driven development and pair programming.
PRODUCT MANAGEMENT
PORTFOLIO
PORTFOLIO
SECURITY
DESIGN
STREAMING
GOOD DAY
SOUND
LOGO MAKER
BAILEY


Have you ever done anything like this?
$marshaller = new CrudRouteMarshaller(
$router, new RouteInflector(), Post::class
);
$marshaller->addViewRoute();
$routeCollection = $router->getRoutes();
$routeCollection->refreshNameLookups();
assertThat($routeCollection->hasNamedRoute("posts.view"), is(true));
$marshaller = new CrudRouteMarshaller(
$router, new RouteInflector(), Post::class
);
$marshaller->addEditRoute();
$routeCollection = $router->getRoutes();
$routeCollection->refreshNameLookups();
assertThat($routeCollection->hasNamedRoute("posts.edit"), is(true));


--- layout: post status: publish published: true title: NLCS Game 2 Post-Game Show - Episode 7.64 author: display_name: Corey Fineran login: Corey email<EMAIL_ADDRESS>url: '' author_login: Corey author_email<EMAIL_ADDRESS>wordpress_id: 11545 wordpress_url: http://ivyenvy.com/?p=11545 date: '2015-10-19 00:30:30 +0000' date_gmt: '2015-10-19 05:30:30 +0000' categories: - Podcast tags: [] comments: [] ---
On this, the 360th episode of The Ivy Envy Podcast, we recap the first two games of the 2015 NLCS.
The Cubs drop the first two games in New York to the Mets. We talk about the pitching performances by Lester and Arrieta and the disappearance of runs from the Cubs offense.


Nov. 20, 2014: As residents dig out, again, fears of flooding rise
This week, The Buffalo News recounts one of the most memorable storms to strike Western New York. Follow along daily.
Residents searching for any sign of good news on Thursday, Nov. 20, 2014, didn’t get much.
But there was plenty of bad news: It was still next to impossible to get around as roads remained impassable and driving bans remained in effect; in some places, that was extended to a walking ban; roofs on homes and businesses, including nursing homes, began to give way under the weight of the snow, now up to 7 feet in some places; the death toll climbed to 12.
And there was the potential for worse news to come: Predicted temperatures in the 50s a few days later would almost surely mean that once people got out of their homes, they would need to get back in to deal with flooding.
Amid all of this weather-induced trauma, the question that seemed to be occupying the minds of many was whether the Buffalo Bills would play at home as scheduled on Sunday against the New York Jets in snowed-in Orchard Park. By the end of the day, that question was settled when it was announced that the game would be played a day late and in Detroit.
Frustration and desperation began to boil over on Thursday. Local officials, who were hearing complaints from snowbound residents, began bickering with each other and complaining that Erie County was not doing enough to clear the roads.
They also blamed motorists for not heeding driving bans, a theme picked up by Gov. Andrew M. Cuomo and roundly criticized by those who said warnings of what to come were insufficient.
Rosann Sessamen of Lackawanna may have summed up the situation best when she said: “I know it’s an act of God. But this is enough.”
Looking back at Nov. 20, 2014
• Five dead as monster storm dumps historic amount of snow
• Death toll rises to 12; roofs collapse as snow piles up
• Snow band dishing out 4 inches an hour over Southtowns
• Social media magnify power of breathtaking megastorm
• Snow aplenty, but shovels and blowers hardly any
• Dispute arises with county over snow-removal equipment
• For Lancaster crews, it’s ‘the worst’ as fight with snow goes on forever
• In storm-impacted areas, everything’s running low except for snow
• Cheektowaga nursing home residents evacuated after snow causes roof damage
• Trapped at home under mounds of snow, coping becomes necessity
• • •
Click here for additional coverage from our archives.
• • •
Inside The News: Reporters and photographers shared what it was like to live through the storm when you also had to cover it.


Represents a JavaScript array. Usually used in FunctionHandler.
More...
#include <Types.hpp>
|
| | Array (NativeContext Context) |
| | Creates a new array object with the given context. More...
|
| |
| | Array (NativeContext Context, u32 Index) |
| | Creates a new array object with the given context and from the specifiec argument index. More...
|
| |
| void | Initialize () |
| | Initializes internally the array. More...
|
| |
| void | AddString (std::string Value) |
| | Adds (pushes) a std::string to the end of the array. More...
|
| |
| void | AddInt (s64 Value) |
| | Adds (pushes) a signed integer to the end of the array. More...
|
| |
| void | AddUInt (u64 Value) |
| | Adds (pushes) an unsigned integer to the end of the array. More...
|
| |
| void | AddDouble (double Value) |
| | Adds (pushes) a double to the end of the array. More...
|
| |
| void | AddBoolean (bool Value) |
| | Adds (pushes) a boolean to the end of the array. More...
|
| |
| void | AddFunction (NativeFunction Value) |
| | Adds (pushes) an API JS function to the end of the array. More...
|
| |
| void | AddUndefined () |
| | Adds (pushes) an undefined value to the end of the array. More...
|
| |
| void | AddNull () |
| | Adds (pushes) a null value to the end of the array. More...
|
| |
| void | AddNaN () |
| | Adds (pushes) a NaN value to the end of the array. More...
|
| |
| void | Close () |
| | Finishes the array (closes it). More...
|
| |
| std::string | GetString (u32 Index) |
| | Gets the argument at given index as a std::string. No conversions are done to get it. More...
|
| |
| s64 | GetInt (u32 Index) |
| | Gets the argument at given index as a signed integer. No conversions are done to get it. More...
|
| |
| u64 | GetUInt (u32 Index) |
| | Gets the argument at given index as an unsigned integer. No conversions are done to get it. More...
|
| |
| double | GetDouble (u32 Index) |
| | Gets the argument at given index as a double. No conversions are done to get it. More...
|
| |
| bool | GetBoolean (u32 Index) |
| | Gets the argument at given index as a boolean. No conversions are done to get it. More...
|
| |
| Array | GetArray (u32 Index) |
| | Gets the argument at given index as an array. No conversions are done to get it. More...
|
| |
| Object | GetObject (u32 Index) |
| | Gets the argument at given index as an object. No conversions are done to get it. More...
|
| |
| std::string | AsJSON () |
| | Gets the JSON std::string representation of this array. More...
|
| |
| int | GetId () |
| |
| NativeContext | GetContext () |
| |
Represents a JavaScript array. Usually used in FunctionHandler.
◆ Array() [1/2]
Creates a new array object with the given context.
- Parameters
-
| Context | The context to use with the array. |
◆ Array() [2/2]
Creates a new array object with the given context and from the specifiec argument index.
- Parameters
-
| Context | The context to use with the array. |
| Index | The argument index to get it from. |
- Note
- Better to call FunctionHandler.getArray(...) instead!
◆ AddBoolean()
| void bjs::js::Array::AddBoolean |
( |
bool |
Value | ) |
|
Adds (pushes) a boolean to the end of the array.
- Parameters
-
| Value | The boolean value to add. |
◆ AddDouble()
| void bjs::js::Array::AddDouble |
( |
double |
Value | ) |
|
Adds (pushes) a double to the end of the array.
- Parameters
-
| Value | The double value to add. |
◆ AddFunction()
Adds (pushes) an API JS function to the end of the array.
- Parameters
-
| Value | The function to add. |
◆ AddInt()
| void bjs::js::Array::AddInt |
( |
s64 |
Value | ) |
|
Adds (pushes) a signed integer to the end of the array.
- Parameters
-
| Value | The signed integer value to add. |
◆ AddNaN()
| void bjs::js::Array::AddNaN |
( |
| ) |
|
Adds (pushes) a NaN value to the end of the array.
◆ AddNull()
| void bjs::js::Array::AddNull |
( |
| ) |
|
Adds (pushes) a null value to the end of the array.
◆ AddString()
| void bjs::js::Array::AddString |
( |
std::string |
Value | ) |
|
Adds (pushes) a std::string to the end of the array.
- Parameters
-
| Value | The std::string value to add. |
◆ AddUInt()
| void bjs::js::Array::AddUInt |
( |
u64 |
Value | ) |
|
Adds (pushes) an unsigned integer to the end of the array.
- Parameters
-
| Value | The unsigned integer value to add. |
◆ AddUndefined()
| void bjs::js::Array::AddUndefined |
( |
| ) |
|
Adds (pushes) an undefined value to the end of the array.
◆ AsJSON()
| std::string bjs::js::Array::AsJSON |
( |
| ) |
|
Gets the JSON std::string representation of this array.
- Returns
- The JSON representation as a std::string.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ Close()
| void bjs::js::Array::Close |
( |
| ) |
|
Finishes the array (closes it).
- Note
- This should NOT be CALLED if using it from a FunctionHandler.
◆ GetArray()
| Array bjs::js::Array::GetArray |
( |
u32 |
Index | ) |
|
Gets the argument at given index as an array. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as an array.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ GetBoolean()
| bool bjs::js::Array::GetBoolean |
( |
u32 |
Index | ) |
|
Gets the argument at given index as a boolean. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as a boolean.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ GetContext()
◆ GetDouble()
| double bjs::js::Array::GetDouble |
( |
u32 |
Index | ) |
|
Gets the argument at given index as a double. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as a double.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ GetId()
| int bjs::js::Array::GetId |
( |
| ) |
|
◆ GetInt()
| s64 bjs::js::Array::GetInt |
( |
u32 |
Index | ) |
|
Gets the argument at given index as a signed integer. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as a signed integer.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ GetObject()
| Object bjs::js::Array::GetObject |
( |
u32 |
Index | ) |
|
Gets the argument at given index as an object. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as an object.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ GetString()
| std::string bjs::js::Array::GetString |
( |
u32 |
Index | ) |
|
Gets the argument at given index as a std::string. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as a std::string.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ GetUInt()
| u64 bjs::js::Array::GetUInt |
( |
u32 |
Index | ) |
|
Gets the argument at given index as an unsigned integer. No conversions are done to get it.
- Parameters
-
| Index | The index to get the argument from. |
- Returns
- The argument as an unsigned integer.
- Note
- This should ONLY be CALLED if using it from a FunctionHandler.
◆ Initialize()
| void bjs::js::Array::Initialize |
( |
| ) |
|
Initializes internally the array.
- Note
- This should NOT be CALLED manually, as pushing it to FunctionHandler actually calls this.
The documentation for this class was generated from the following file:


Module: Approvability::ActsAsApprovability::Base::Config
- Defined in:
- lib/approvability/acts_as_approvability.rb
Instance Method Summary (collapse)
Instance Method Details
- (Object) acts_as_approvability
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 |
# File 'lib/approvability/acts_as_approvability.rb', line 12 def acts_as_approvability # Flags that a contributor less than an administrator has submitted this attr_accessor :requires_approval # All Approvability models have polymorphic relationships with the Approval model has_many :approvals, as: :approvable # Saves the approval automatically whenever models are flagged with {#requires_approval!} from a controller after_create :create_approval, if: :requires_approval accepts_nested_attributes_for :approvals # Uncomment this if for any reason you want to submit the approval flag via a form # Otherwise be content with using @approval_instnace.requires_approval! in the controller # attr_accessible :requires_approval attr_accessible :approvals_attributes include Approvability::ActsAsApprovability::Base::InstanceMethods end |


Caitlyn Jenner opens up about Vanity Fair cover in I’m A Celebrity
She debuted her new identity on the front of the magazine in June 2015.
Caitlyn Jenner has said that her Vanity Fair cover shoot was a four-letter rebuke to the people who were critical of her decision to transition gender.
The 70-year-old Olympic gold medalist, born Bruce, debuted her new identity in a corset on the cover of the magazine in June 2015.
She said she had felt it was “extraordinarily important” that she tried to make an impact on social media after coming out as transgender.
She told her campmates on I’m A Celebrity… Get Me Out Of Here! that the image had been a direct message to the “millions” who had said “terrible things” about her.
She said: “Transitioning and trying to make an impact (on) social media is extraordinarily important.
“As soon as the cover of Vanity Fair broke, in the next four hours and one minute, it broke the world record for the fastest to one million followers on Twitter.”
Jenner has six biological children – Burt and Cassandra with first wife Chrystie Scott, Brandon and Brody with second wife Linda Thompson, and Kendall and Kylie with third wife Kris Jenner.
Girls Aloud star Nadine Coyle, 34, said she remembered where she was on the day the cover was published.
“It’s a big thing,” agreed EastEnders actress Jacqueline Jossa.
Jenner added: “For me this was a big f*** you to the millions and millions of people out there that had said terrible things about me. And it just came out and it just shocked them.”
She also explained to Jossa how she had come to transition.
She said: “Over many, many, years I had a lot (of surgery) but then near the end it went pretty quickly because you can do your face and your chest all at the same time which they did.

“And in my case I was on oestrogen back in the 80s and had a little 36/38B and then I met Kris and had them chopped off.”
She quipped: “I’m so confused in my life.”
“And then the second time round 25 years later I was back on oestrogen obviously and they came back – some but not much.
“So I really had to have them done so it is kind of past the point of no return.”
Jenner also compared Jossa to her daughter Kylie after the soap star bravely took on a Bushtucker Trial.
Later, Jossa said of Jenner: “I love the fact that she talks so openly and she feels like she can trust us and speak to us so openly, and she puts everything into perspective as well.”
She added that “the amount of strength that woman has is amazing”.
The latest episode of I’m A Celebrity saw Jossa and Ian Wright face a stomach-churning trial in which they had to clamber through tunnels filled with crickets, worms, toads and spiders.
I’m A Celebrity… Get Me Out Of Here! continues on ITV.


# Things I saw
# at NICAR 2017
# First: ALL THE LINKS
* All of these links (and more) at [Chrys Wu's site](http://blog.chryswu.com/2017/03/02/nicar17-slides-links-tutorials-nicar17/)
* [My actual notes](https://docs.google.com/document/d/1DZmUil3_GBK8JgQcDGFgxWOcw1Gbg23fRilhrt6HC3Y/edit) from the sessions I attended
* [These slides are at chagan.github.io/nicar-summary-2017](https://chagan.github.io/nicar-summary-2017/#/)
# DATA GIFS!
* [Slides](http://lenagroeger.com/datagifs/#/)
* [Repo](https://github.com/lenagroeger/gifs)
# (Easier) Space Journalism!
* [Planet Labs](https://www.dropbox.com/sh/jhqtg8o67s6bnug/AAAS_zIT5symkflXBx9DDhT9a?dl=0&preview=SaraSchnadt_DataJournalismFromSpace_NICAR2017.pdf)
* [Google Earth Engine](https://docs.google.com/presentation/d/1jznHMLOJTpKcv-Gmpct12-BKA6ve_qVOibFB_HNAX6s/edit#slide=id.g16dde4ccec_0_0)
# User Testing
* “I am not my users”
* Average person can figure out how to use the thing to do the thing
* After 2 to 3 people, see lot of small things
* [Slides](https://drive.google.com/file/d/0BygeDfZ5FPmTVno3RTNSbkpka0U/view)
# Personalized Interactive Journeys
* Using Choose Your Own Adventure in the newsroom
* Can give users perspective, empathy, by stepping into another's shoes
* [Slides](https://docs.google.com/presentation/d/1UNk8zwalEJtt83SqGAEvMs2Y70e9dwsxFhlALktxW-0/edit#slide=id.p)
# Graph Databases
* Map connections between people/groups
* [Slides](https://docs.google.com/presentation/d/18fW8NkWxDIDZOVFvhT5J19V5AbGKYG7D35_CtjNO_CI/edit?usp=sharing)
![Alt text](images/younger.png)
# Making Data Approachable for Younger Audiences
* [Slides](https://drive.google.com/file/d/0B-x9LJOg77smSFVZempkbmJSemM/view)
# 30 Tools in 60 Minutes
* Roundup of new/useful tools (some that we already use)
*<EMAIL_ADDRESS># Klaxon
* Tool from the Marshall Project to monitor websites for changes
* [Slides](https://docs.google.com/presentation/d/1anjR5isAQLK0ujBxn3qPwXPj9IAQUXP_4ca1RCY1qog/edit#slide=id.g16f93938e1_1_63)
* [Website](https://www.newsklaxon.org/)


@Target(value=TYPE)
@Retention(value=RUNTIME)
@Documented
public @interface CacheConfig
@CacheConfig
provides a mechanism for sharing common cache-related
settings at the class level.
When this annotation is present on a given class, it provides a set of default settings for any cache operation defined in that class.
| 限定符和类型 | 可选元素和说明 |
|---|---|
java.lang.String |
cacheManager
The bean name of the custom
CacheManager to use to
create a default CacheResolver if none
is set already. |
java.lang.String[] |
cacheNames
Names of the default caches to consider for caching operations defined
in the annotated class.
|
java.lang.String |
cacheResolver
The bean name of the custom
CacheResolver to use. |
java.lang.String |
keyGenerator
The bean name of the default
KeyGenerator to
use for the class. |
public abstract java.lang.String[] cacheNames
If none is set at the operation level, these are used instead of the default.
May be used to determine the target cache (or caches), matching the qualifier value or the bean names of a specific bean definition.
public abstract java.lang.String keyGenerator
KeyGenerator
to
use for the class.
If none is set at the operation level, this one is used instead of the default.
The key generator is mutually exclusive with the use of a custom key. When such key is defined for the operation, the value of this key generator is ignored.
public abstract java.lang.String cacheManager
CacheManager
to use to
create a default CacheResolver
if none
is set already.
If no resolver and no cache manager are set at the operation level, and no cache
resolver is set via cacheResolver()
, this one is used instead of the default.
SimpleCacheResolver
public abstract java.lang.String cacheResolver
CacheResolver
to use.
If no resolver and no cache manager are set at the operation level, this one is used instead of the default.


Pattern
Pattern is the repetition of elements in a recurring sequence. A pattern can be composed of recurring shapes or elements, even colors. Whether you realize it or not, pattern is all around you. From the tartan of your neighbor's kilt to the Greek meander on your mom's favorite China, pattern is present in nearly all art forms. Let's think about a very simple example, a series of boxes, such as the ones below. There is a pattern because every third box is the same, creating a pattern of three boxes which are repeated.
Pattern isn't restricted to manmade artworks alone. Pattern can be found prolifically in nature. Take for example the spots on a cheetah. We call that a pattern because it is quite repetitive. It isn't a perfect pattern because each spot is unique, so there is no repetition, however, to the observer it appears repetitive. How about we look at a very nice pattern. The Fibonacci sequence. The Golden Formula, which can be found in a plethora of areas, from the humble pinecone to the sea shell, dictates many patterns in nature. Let's look at its beautiful form.
\[F_n=\frac{\varphi^n-\Psi^n}{\varphi-\psi}\]
Boom. Beautiful. That's all the art you need to know. I kid, but in case you wanted it there's the Fibonacci sequence formula. Just look it up on Wikipedia if you want to know what the Greek letters stand for. Anyway, my point is that pattern is all around us, from the natural world to the artworks we make. It can be represented in art in a variety of ways, from meandering lines to simple things, such as dots repeating. Pattern is beautiful and pattern is nearly omnipresent.


Home
About
Shop
News
Contact
Scotty is a beast
these are the items
these are the items
these are the items
these are the items