Source

JythonBook / SimpleWebApps.rst

Josh Juneau 8c33c08 




















































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































   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
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
Chapter 13: Simple Web Applications - *Final v1.0*
++++++++++++++++++++++++++++++++++++++++++++++++++

One of the major benefits of using Jython is the ability to make
use of Java platform capabilities programming in the Python
programming language instead of Java. In the Java world today, the
most widely used web development technique is the Java servlet. Now
in JavaEE, there are techniques and frameworks used so that we can
essentially code HTML or other markup languages as opposed to
writing pure Java servlets. However, sometimes writing a pure Java
servlet still has its advantages. We can use Jython to write
servlets and this adds many more advantages above and beyond what
Java has to offer because now we can make use of Python language
features as well. Similarly, we can code web start applications
using Jython instead of pure Java to make our lives easier. Coding
these applications in pure Java has proven sometimes to be a
difficult and sometimes grueling task. We can use some of the
techniques available in Jython to make our lives easier. We can
even code WSGI applications with Jython making use of the *modjy*
integration in the Jython project.

In this chapter, we will cover three techniques for coding simple
web applications using Jython: servlets, web start, and WSGI. We’ll
get into details on using each of these different techniques here,
but we will discuss deployment of such solutions in Chapter 17.

Servlets
========

Servlets are a Java platform technology for building web-based
applications. They are a platform- and server-independent
technology for serving content to the web. If you are unfamiliar
with Java servlets, it would be worthwhile to learn more about
them. An excellent resource is wikipedia
(http://en.wikipedia.org/wiki/Java_Servlet); however, there are a
number of other great places to find out more about Java servlets.
Writing servlets in Jython is a very productive and easy way to
make use of Jython within a web application. Java servlets are
rarely written using straight Java anymore. Most Java developers
make use of Java Server Pages (JSP), Java Server Faces (JSF), or
some other framework so that they can use a markup language to work
with web content as opposed to only working with Java code.
However, in some cases it is still quite useful to use a pure Java
servlet. For these cases we can make our lives easier by using
Jython instead. There are also great use-cases for JSP; similarly,
we can use Jython for implementing the logic in our JSP code. The
latter technique allows us to apply a model-view-controller (MVC)
paradigm to our programming model, where we separate our front-end
markup from any implementation logic. Either technique is rather
easy to implement, and you can even add this functionality to any
existing Java web application without any trouble.

Another feature offered to us by Jython servlet usage is dynamic
testing. Because Jython compiles at runtime, we can make code
changes on the fly without recompiling and redeploying our web
application. This can make it very easy to test web applications,
because usually the most painful part of web application
development is the wait time between deployment to the servlet
container and testing.

Configuring Your Web Application for Jython Servlets
----------------------------------------------------

Very little needs to be done in any web application to make it
compatible for use with Jython servlets. Jython contains a built-in
class named *PyServlet* that facilitates the creation of Java
servlets using Jython source files. We can make use of PyServlet
quite easily in our application by adding the necessary XML
configuration into the application’s web.xml descriptor such that
the *PyServlet* class gets loaded at runtime and any file that
contains the *.py* suffix will be passed to it. Once this
configuration has been added to a web application, and *jython.jar*
has been added to the CLASSPATH then the web application is ready
to use Jython servlets. See Listing 13-1.

*Listing 13-1. Making a Web Application Compatible with Jython*
::
    
    <servlet>
        <servlet-name>PyServlet</servlet-name>
        <servlet-class>org.python.util.PyServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>PyServlet</servlet-name>
        <url-pattern>*.py</url-pattern>
    </servlet-mapping>

Any servlet that is going to be used by a Java servlet container
also needs to be added to the *web.xml* file as well, since this
allows for the correct mapping of the servlet via the URL. For the
purposes of this book, we will code a servlet named
*NewJythonServlet* in the next section, so the following XML
configuration will need to be added to the web.xml file. See
Listing 13-2.

*Listing 13-2. Coding a Jython Servlet*
::
    
    <servlet>
        <servlet-name>NewJythonServlet</servlet-name>
        <servlet-class>NewJythonServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>NewJythonServlet</servlet-name>
        <url-pattern>/NewJythonServlet</url-pattern>
    </servlet-mapping>

Writing a Simple Servlet
------------------------

In order to write a servlet, we must have the
*javax.servlet.http.HttpServlet* abstract Java class within our
CLASSPATH so that it can be extended by our Jython servlet to help
facilitate the code. This abstract class, along with the other
servlet implementation classes, is part of the *servlet-api.jar*
file. According to the abstract class, there are two methods that
we should override in any Java servlet, those being *doGet* and
*doPost*. The former performs the HTTP GET operation while the
latter performs the HTTP POST operation for a servlet. Other
commonly overridden methods include *doPut*, *doDelete*, and
*getServletInfo*. The first performs the HTTP PUT operation, the
second performs the HTTP DELETE operation, and the last provides a
description for a servlet. In the following example, and in most
use-cases, only the *doGet* and *doPost* are used.

Let’s first show the code for an extremely simple Java servlet.
This servlet contains no functionality other than printing its name
along with its location in the web application to the screen.
Following that code we will take a look at the same servlet coded
in Jython for comparison (Listing 13-3).

*Listing 13-3. NewJavaServlet.java*
::
    
    import java.io.IOException;
    import java.io.PrintWriter;
    import javax.servlet.ServletException;
    import javax.servlet.http.HttpServlet;
    import javax.servlet.http.HttpServletRequest;
    import javax.servlet.http.HttpServletResponse;
    
    public class NewJavaServlet extends HttpServlet {
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
        throws ServletException, IOException {
            response.setContentType("text/html;charset=UTF-8");
            PrintWriter out = response.getWriter();
            try {
                out.println("<html>");
                out.println("<head>");
                out.println("<title>Servlet NewJavaServlet Test</title>");
                out.println("</head>");
                out.println("<body>");
                out.println("<h1>Servlet NewJavaServlet at " +
                request.getContextPath () + "</h1>");
                out.println("</body>");
                out.println("</html>");
            } finally {
                out.close();
            }
        }
        
        @Override
        protected void doGet(HttpServletRequest request,
        HttpServletResponse response)
        throws ServletException, IOException {
            processRequest(request, response);
        }
        
        @Override
        protected void doPost(HttpServletRequest request,
        HttpServletResponse response)
        throws ServletException, IOException {
            processRequest(request, response);
        }
        
        @Override
        public String getServletInfo() {
            return "Short description";
        }
    }

All commenting has been removed from the code in an attempt to make
the code a bit shorter. Now, Listing 13-4 is the equivalent servlet
code written in Jython.

*Listing 13-4.*
::
    
    from javax.servlet.http import HttpServlet
    
    class NewJythonServlet (HttpServlet):
        def doGet(self,request,response):
            self.doPost (request,response)
            
        def doPost(self,request,response):
            toClient = response.getWriter()
            response.setContentType ("text/html")
            toClient.println ("<html><head><title>Jython Servlet Test</title>"
            +
            "<body><h1>Servlet Jython Servlet at" +
            request.getContextPath() + "</h1></body></html>")
            
        def getServletInfo(self):
            return "Short Description"

Not only is the concise code an attractive feature, but also the
easy development lifecycle for working with dynamic servlets. As
stated previously, there is no need to redeploy each time you make
a change because of the compile at runtime that Jython offers.
Simply change the Jython servlet, save, and reload the webpage to
see the update. If you begin to think about the possibilities
you’ll realize that the code above is just a basic example, you can
do anything in a Jython servlet that you can with Java and even
most of what can be done using the Python language as well.

To summarize the use of Jython servlets, you simply include
*jython.jar* and *servlet-api.jar* in your CLASSPATH. Add necessary
XML to the web.xml, and then finally code the servlet by extending
the javax.servlet.http.HttpServlet abstract class.

Using JSP with Jython
---------------------

Harnessing Jython servlets allows for a more productive development
lifecycle, but in certain situations Jython code may not be the
most convenient way to deal with front-facing web code. Sometimes
using a markup language such as HTML works better for developing
sophisticated front-ends. For instance, it is easy enough to
include JavaScript code within a Jython servlet. However, all of
the JavaScript code would be written within the context of a
String. Not only does this eliminate the usefulness of an IDE for
situations such as semantic code coloring and auto completion, but
it also makes code harder to read and understand. Cleanly
separating such code from Jython or Java makes code more clear to
read, and easier to maintain in the long run. One possible solution
would be to choose from one of the Python template languages such
as Django, but using Java Server Pages (JSP) technology can also be
a nice solution.

Using a JSP allows one to integrate Java code into HTML markup in
order to generate dynamic page content. We are not fans of JSP.
There, we said it: JSP can make code a living nightmare if the
technology is not used correctly. Although JSP can make it very
easy to mix JavaScript, HTML, and Java into one file, it can make
maintenance very difficult. Mixing Java code with HTML or
JavaScript is a bad idea. The same would also be true for mixing
Jython and HTML or JavaScript.

The Model-View-Controller (MVC) paradigm allows for clean
separation between logic code, such as Java or Jython, and markup
code such as HTML. JavaScript is always gets grouped into the same
arena as HTML because it is a client-side scripting language. In
other words, JavaScript code should also be separated from the
logic code. In thinking about MVC, the controller code would be the
markup and JavaScript code used to capture data from the end-user.
Model code would be the business logic that manipulates the data.
Model code is contained within our Jython or Java. The view would
be the markup and JavaScript displaying the result.

Clean separation using MVC can be achieved successfully by
combining JSP with Jython servlets. In this section we will take a
look at a simple example of how to do so. As with many of the other
examples in this text it will only brush upon the surface of great
features that are available. Once you learn how to make use of JSP
and Jython servlets you can explore further into the technology.

Configuring for JSP
~~~~~~~~~~~~~~~~~~~

There is no real configuration above and beyond that of configuring
a web application to make use of Jython servlets. Add the necessary
XML to the web.xml deployment descriptor, include the correct JARs
in your application, and begin coding. What is important to note is
that the *.py* files that will be used for the Jython servlets must
reside within your CLASSPATH. It is common for the Jython servlets
to reside in the same directory as the JSP web pages themselves.
This can make things easier, but it can also be frowned upon
because this concept does not make use of packages for organizing
code. For simplicity sake, we will place the servlet code into the
same directory as the JSP, but you can do it differently.

Coding the Controller/View
~~~~~~~~~~~~~~~~~~~~~~~~~~

The view portion of the application will be coded using markup and
JavaScript code. Obviously, this technique utilizes JSP to contain
the markup, and the JavaScript can either be embedded directly into
the JSP or reside in separate *.js* files as needed. The latter is
the preferred method in order to make things clean, but many web
applications embed small amounts of JavaScript within the pages
themselves.

The JSP in this example is rather simple, there is no JavaScript in
the example and it only contains a couple of input text areas. This
JSP will include two forms because we will have two separate submit
buttons on the page. Each of these forms will redirect to a
different Jython servlet, which will do something with the data
that has been supplied within the input text. In our example, the
first form contains a small textbox in which the user can type any
text that will be redisplayed on the page once the corresponding
submit button has been pressed. Very cool, eh? Not really, but it
is of good value for learning the correlation between JSP and the
servlet implementation. The second form contains two text boxes in
which the user will place numbers; hitting the submit button in
this form will cause the numbers to be passed to another servlet
that will calculate and return the sum of the two numbers. Listing
13-5 is the code for this simple JSP.

*Listing 13-5. JSP Code for a Simple Controller/Viewer Application*

*testJSP.jsp*
::
    
    <%@page contentType="text/html" pageEncoding="UTF-8"%>
    <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
    "http://www.w3.org/TR/html4/loose.dtd">
    <%@ taglib prefix="c" uri="http://java.sun.com/jstl/core" %>
    <html>
        <head>
            <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
            <title>Jython JSP Test</title>
        </head>
        <body>
            <form method="GET" action="add_to_page.py">
                <input type="text" name="p">
                <input type="submit">
            </form>
            <br/>
            <p>${page_text}</p>
            <br/>
            <form method="GET" action="add_numbers.py">
                <input type="text" name="x">
                +
                <input type="text" name="y">
                =
                ${sum}
                <br/>
                <input type="submit" title="Add Numbers">
            </form>
        </body>
    </html>


In this JSP example, you can see that the first form redirects to a
Jython servlet named
*add_to_page.py, which plays the role of the controller*. In this
case, the text that is contained within the input textbox named *p*
will be passed into the servlet, and redisplayed in on the page.
The text to be redisplayed will be stored in an attribute named
*page_text*, and you can see that it is referenced within the JSP
page using the ${} notation. Listing 13-6 is the code for
*add_to_page.py*.

*Listing 13-6. A Simple Jython Controller Servlet*
::
    
    #######################################################################
    # add_to_page.py
    #
    # Simple servlet that takes some text from a web page and redisplays
    # it.
    #######################################################################
    import java, javax, sys
    
    class add_to_page(javax.servlet.http.HttpServlet):
        def doGet(self, request, response):
            self.doPost(request, response)
        
        def doPost(self, request, response):
            addtext = request.getParameter("p")
            if not addtext:
                addtext = ""
            request.setAttribute("page_text", addtext)
            dispatcher = request.getRequestDispatcher("testJython.jsp")
            dispatcher.forward(request, response)



Quick and simple, the servlet takes the request and obtains value
contained within the parameter *p*. It then assigns that value to a
variable named *addtext*. This variable is then assigned to an
attribute in the request named *page_text* and forwarded back to
the *testJython.jsp* page. The code could just as easily have
forwarded to a different JSP, which is how we’d go about creating a
more in-depth application.

The second form in our JSP takes two values and returns the
resulting sum to the page. If someone were to enter text instead of
numerical values into the text boxes then an error message would be
displayed in place of the sum. While very simplistic, this servlet
demonstrates that any business logic can be coded in the servlet,
including database calls, and so on. See Listing 13-7.

*Listing 13-7. Jython Servlet Business Logic*
::
    
    #######################################################################
    # add_numbers.py
    #
    # Calculates the sum for two numbers and returns it.
    #######################################################################
    import javax
    
    class add_numbers(javax.servlet.http.HttpServlet):
        def doGet(self, request, response):
            self.doPost(request, response)
        
        def doPost(self, request, response):
            x = request.getParameter("x")
            y = request.getParameter("y")
            if not x or not y:
                sum = "<font color='red'>You must place numbers in each value box</font>"
            else:
                try:
                    sum = int(x) + int(y)
                except ValueError, e:
                    sum = "<font color='red'>You must place numbers only in each value box</font>"
            request.setAttribute("sum", sum)
            
            dispatcher = request.getRequestDispatcher("testJython.jsp")
            dispatcher.forward(request, response)



If we add the JSP and the servlets to the web application we
created in the previous Jython Servlet section, then this example
should work out-of-the-box.

It is also possible to embed code into Java Server Pages by using
various template tags known as scriptlets to enclose the code. In
such cases, the JSP must contain Java code unless a special
framework such as the Bean Scripting Framework
(http://jakarta.apache.org/bsf/) is used along with JSP. For more
details on using Java Server Pages, please take a look at the Sun
Microsystems JSP documentation
(http://java.sun.com/products/jsp/docs.html) or pick up a book such
as
*Beginning JSP, JSF and Tomcat Web Development: From Novice to Professional* from
Apress.

Applets and Java Web Start
==========================

At the time of this writing, applets in Jython 2.5.0 are not yet an
available option. This is because applets must be statically
compiled and available for embedding within a webpage using the
*<applet>* or *<object>* tag. The static compiler known as
*jythonc***has been removed in Jython 2.5.0 in order to make way
for better techniques. Jythonc was good for performing certain
tasks, such as static compilation of Jython applets, but it created
a disconnect in the development lifecycle as it was a separate
compilation step that should not be necessary in order to perform
simple tasks such as Jython and Java integration. In a future
release of Jython, namely 2.5.1 or another release in the near
future, a better way to perform static compilation for applets will
be included.

For now, in order to develop Jython applets you will need to use a
previous distribution including *jythonc* and then associate them
to the webpage with the *<applet>* or *<object>* tag. In Jython,
applets are coded in much the same fashion as a standard Java
applet. However, the resulting lines of code are significantly
smaller in Jython because of its sophisticated syntax. GUI
development in general with Jython is a big productivity boost
compared to developing a Java Swing application for much the same
reason. This is why coding applets in Jython is a viable solution
and one that should not be overlooked.

Another option for distributing GUI-based applications on the web
is to make use of the Java Web Start technology. The only
disadvantage of creating a web start application is that it cannot
be embedded directly into any web page. A web start application
downloads content to the client’s desktop and then runs on the
client’s local JVM. Development of a Java Web Start application is
no different than development of a standalone desktop application.
The user interface can be coded using Jython and the Java Swing
API, much like the coding for an applet user interface. Once you’re
ready to deploy a web start application then you need to create a
Java Network Launching Protocol (JNLP) file that is used for
deployment and bundle it with the application. After that has been
done, you need to copy the bundle to a web server and create a web
page that can be used to launch the application.

In this section we will develop a small web start application to
demonstrate how it can be done using the object factory design
pattern and also using pure Jython along with the standalone Jython
JAR file for distribution. Note that there are probably other ways
to achieve the same result and that these are just a couple of
possible implementations for such an application.

Coding a Simple GUI-Based Web Application
-----------------------------------------

The web start application that we will develop in this
demonstration is very simple, but they can be as advanced as you’d
like in the end. The purpose of this section is not to show you how
to develop a web-based GUI application, but rather, the process of
developing such an application. You can actually take any of the
Swing-based applications that were discussed in the GUI chapter and
deploy them using web start technology quite easily. As stated in
the previous section, there are many different ways to deploy a
Jython web start application. We prefer to make use of the object
factory design pattern to create simple Jython Swing applications.
However, it can also be done using all .py files and then
distributed using the Jython stand-alone JAR file. We will discuss
each of those techniques in this section. We find that if you are
mixing Java and Jython code then the object factory pattern works
best. The JAR method may work best for you if developing a strictly
Jython application.

Object Factory Application Design
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

The application we’ll be developing in this section is a simple GUI
that takes a line of text and redisplays it in JTextArea. We used
Netbeans 6.7 to develop the application, so some of this section
may reference particular features that are available in that IDE.
To get started with creating an object factory web start
application, we first need to create a project. We created a new
Java application in Netbeans named *JythonSwingApp* and then added
*jython.jar* and *plyjy.jar* to the classpath.

First, create the *Main.java* class which will really be the driver
for the application. The goal for Main.java is to use the Jython
object factory pattern to coerce a Jython-based Swing application
into Java. This class will be the starting point for the
application and then the Jython code will perform all of the work
under the covers. Using this pattern, we also need a Java interface
that can be implemented via the Jython code, so this example also
uses a very simple interface that defines a *start()* method which
will be used to make our GUI visible. Lastly, the Jython class
named below is the code for our *Main.java* driver and the Java
interface. The directory structure of this application is as shown
in Listing 13-8.

*Listing 13-8. Object Factory Application Code*

    **JythonSwingApp**
        **JythonSimpleSwing.py**
        
        **jythonswingapp**
            Main.java
            
            **jythonswingapp.interfaces**
            
            JySwingType.java

*Main.java*
::
    
    package jythonswingapp;
    
    import jythonswingapp.interfaces.JySwingType;
    import org.plyjy.factory.JythonObjectFactory;
    
    public class Main {
        JythonObjectFactory factory;
        
        public static void invokeJython(){
            JySwingType jySwing = (JySwingType) JythonObjectFactory
            .createObject(JySwingType.class, "JythonSimpleSwing");
            jySwing.start();
        }
        
        public static void main(String[] args) {
            invokeJython();
        }
    }



As you can see, *Main.java* doesn’t do much else except coercing
the Jython module and invoking the *start()* method. In Listing
13-9, you will see the *JySwingType.java* interface along with the
implementation class that is obviously coded in Jython.

*Listing 13-9. JySwingType.java Interface and Implementation*

*JySwingType.java*
::
    
    package jythonswingapp.interfaces;
    
    public interface JySwingType {
        public void start();
    }


*JythonSimpleSwing.py*
::
    
    import javax.swing as swing
    import java.awt as awt
    from jythonswingapp.interfaces import JySwingType
    import add_player as add_player
    import Player as Player
    
    class JythonSimpleSwing(JySwingType, object):
        def __init__(self):
            self.frame=swing.JFrame(title="My Frame", size=(300,300))
            self.frame.defaultCloseOperation=swing.JFrame.EXIT_ON_CLOSE
            self.frame.layout=awt.BorderLayout()
            self.panel1=swing.JPanel(awt.BorderLayout())
            self.panel2=swing.JPanel(awt.GridLayout(4,1))
            self.panel2.preferredSize = awt.Dimension(10,100)
            self.panel3=swing.JPanel(awt.BorderLayout())
            self.title=swing.JLabel("Text Rendering")
            self.button1=swing.JButton("Print Text", actionPerformed=self.printMessage)
            self.button2=swing.JButton("Clear Text", actionPerformed=self.clearMessage)
            self.textField=swing.JTextField(30)
            self.outputText=swing.JTextArea(4,15)
            
            self.panel1.add(self.title)
            self.panel2.add(self.textField)
            self.panel2.add(self.button1)
            self.panel2.add(self.button2)
            self.panel3.add(self.outputText)
            
            self.frame.contentPane.add(self.panel1, awt.BorderLayout.PAGE_START)
            self.frame.contentPane.add(self.panel2, awt.BorderLayout.CENTER)
            self.frame.contentPane.add(self.panel3, awt.BorderLayout.PAGE_END)
            
        def start(self):
            self.frame.visible=1
            
        def printMessage(self,event):
            print "Print Text!"
            self.text = self.textField.getText()
            self.outputText.append(self.text)
            
        def clearMessage(self, event):
            self.outputText.text = ""



If you are using Netbeans, when you clean and build your project a
JAR file is automatically generated for you. However, you can
easily create a JAR file at the command-line or terminal by
ensuring that the *JythonSimpleSwing.py* module resides within your
classpath and using the *java -jar* option. Another nice feature of
using an IDE such as Netbeans is that you can make this into a
web-start application by going into the project properties and
checking a couple of boxes. Specifically, if you go into the
project properties and select *Application - Web Start* from the
left-hand menu, then check the *Enable Web Start* option then the
IDE will take care of generating the necessary files to make this
happen. Netbeans also has the option to self sign the JAR file
which is required to run most applications on another machine via
web start. Go ahead and try it out, just ensure that you clean and
build your project again after making the changes.

To manually create the necessary files for a web start application,
you’ll need to generate two additional files that will be placed
outside of the application JAR. Create the JAR for your project as
you would normally do, and then create a corresponding JNLP file
which is used to launch the application, and an HTML page that will
reference the JNLP. The HTML page obviously is where you’d open the
application if running it from the web. Listing 13-10 is some
example code for generating a JNLP as well as embedding in HTML.

*Listing 13-10. JNLP Code for Web Start*

*launch.jnlp*
::
    
    <?xml version="1.0" encoding="UTF-8" standalone="no"?>
    <jnlp codebase="file:/path-to-jar/" href="launch.jnlp" spec="1.0+">
        <information>
            <title>JythonSwingApp</title>
            <vendor>YourName</vendor>
            <homepage href=""/>
            <description>JythonSwingApp</description>
            <description kind="short">JythonSwingApp</description>
        </information>
        <security>
            <all-permissions/>
        </security>
        <resources>
            <j2se version="1.5+"/>
            <jar eager="true" href="JythonSwingApp.jar" main="true"/>
            <jar href="lib/PlyJy.jar"/>
            <jar href="lib/jython.jar"/>
        </resources>
        <application-desc main-class="jythonswingapp.Main">
        </application-desc>
    </jnlp>


*launch.html*
::
    
    <html>
        <head>
            <title>Test page for launching the application via JNLP</title>
        </head>
        <body>
            <h3>Test page for launching the application via JNLP</h3>
            <a href="launch.jnlp">Launch the application</a>
            <!-- Or use the following script element to launch with the
            Deployment Toolkit -->
            <!-- Open the deployJava.js script to view its documentation -->
            <!--
            <script src="http://java.com/js/deployJava.js"></script>
            <script>
            var url="http://[fill in your URL]/launch.jnlp"
            deployJava.createWebStartLaunchButton(url, "1.6")
            </script>
            -->
        </body>
    </html>



In the end, Java web start is a very good way to distribute Jython
applications via the web.

Distributing via Standalone JAR
-------------------------------

It is possible to distribute a web start application using the
Jython standalone JAR option. To do so, you must have a copy of the
Jython standalone JAR file, explode it, and add your code into the
file, then JAR it back up to deploy. The only drawback to using
this method is that you may need to ensure files are in the correct
locations in order to make it work correctly, which can sometimes
be tedious.

In order to distribute your Jython applications via a JAR, first
download the Jython standalone distribution. Once you have this,
you can extract the files from the *jython.jar* using a tool to
expand the JAR such as Stuffit or 7zip. Once the JAR has been
exploded, you will need to add any of your *.py* scripts into the
*Lib* directory, and any Java classes into the root. For instance,
if you have a Java class named *org.jythonbook.Book*, you would
place it into the appropriate directory according to the package
structure. If you have any additional JAR files to include with
your application then you will need to make sure that they are in
your classpath. Once you’ve completed this setup, JAR your
manipulated standalone Jython JAR back up into a ZIP format using a
tool such as those noted before. You can then rename the ZIP to a
JAR. The application can now be run using the java “-jar” option
from the command line using an optional external *.py* file to
invoke your application.

::
    
    $ java -jar newStandaloneJar.jar {optional .py file}

This is only one such technique used to make a JAR file for
containing your applications. There are other ways to perform such
techniques, but this seems to be the most straight forward and
easiest to do.

WSGI and Modjy
==============

WSGI, also known as the *Web Server Gateway Interface*, is a
low-level API that provides communication between a web server and
a web application. Actually, WSGI is a lot more than that and you
can actually write complete web applications using WSGI. However,
WSGI is more of a standard interface to call python methods and
functions. Python PEP 333 specifies the proposed standard interface
between web servers and Python web applications or frameworks, to
promote web application portability across a variety of web
servers.

This section will show you how to utilize WSGI to create a very
simple “Hello Jython” application by utilizing *modjy*. Modjy is an
implementation of a WSGI compliant gateway/server for Jython, built
on Java/J2EE servlets. Taken from the modjy website
(http://opensource.xhaus.com/projects/modjy/wiki), modjy is
characterized as follows:

.. note::
    Jython WSGI applications run inside a Java/J2EE container and incoming requests are handled by the servlet container. The container is configured to route requests to the modjy servlet. The modjy servlet then creates an embedded Jython interpreter inside the servlet container, and loads a configured Jython web application. For instance, a Django application can be loaded via modjy. The modjy servlet then delegates the requests to the configured WSGI application or framework. Lastly, the WSGI response is routed back to the client through the servlet container.


Running a Modjy Application in Glassfish
----------------------------------------

To run a modjy application in any Java servlet container, the first
step is to create a Java web application that will be packaged up
as a WAR file. You can create an application from scratch or use an
IDE such as Netbeans 6.7 to assist. Once you’ve created your web
application, ensure that *jython.jar* resides in the CLASSPATH as
modjy is now part of Jython as of 2.5.0. Lastly, you will need to
configure the modjy servlet within the application deployment
descriptor (web.xml). In this example, we took the modjy sample
application for Google App Engine and deployed it in my local
Glassfish environment.

To configure the application deployment descriptor with modjy, we
simply configure the modjy servlet, provide the necessary
parameters, and then provide a servlet mapping. In the
configuration file shown in Listing 13-11, note that the modjy
servlet class is *com.xhaus.modjy.ModjyServlet*. The first
parameter you will need to use with the servlet is named
*python.home*. Set the value of this parameter equal to your Jython
home. Next, set the parameter *python.cachedir.skip* equal to true.
The *app_filename* parameter provides the name of the application
callable. Other parameters will be set up the same for each modjy
application you configure. The last piece of the web.xml that needs
to be set up is the servlet mapping. In the example, we set up all
URLs to map to the modjy servlet.

*Listing 13-11. Configuring the Modjy Servlet*

*web.xml*
::
    
    <?xml version="1.0" encoding="ISO-8859-1"?>
    <!DOCTYPE web-app
    PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
    "http://java.sun.com/dtd/web-app_2_3.dtd">
    <web-app>
        <display-name>modjy demo application</display-name>
        <description>
            modjy WSGI demo application
        </description>
        
        <servlet>
            <servlet-name>modjy</servlet-name>
            <servlet-class>com.xhaus.modjy.ModjyJServlet</servlet-class>
            
            <init-param>
                <param-name>python.home</param-name>
                <param-value>/Applications/jython/jython2.5.0/</param-value>
            </init-param>
            
            <init-param>
                <param-name>python.cachedir.skip</param-name>
                <param-value>true</param-value>
            </init-param>
            <!--
            There are two different ways you can specify an application to
            modjy
            1. Using the app_import_name mechanism
            2. Using a combination of
            app_directory/app_filename/app_callable_name
            Examples of both are given below
            See the documentation for more details.
            http://modjy.xhaus.com/locating.html#locating_callables
            -->
            <!--
            This is the app_import_name mechanism. If you specify a value
            for this variable, then it will take precedence over the other
            mechanism
            <init-param>
                <param-name>app_import_name</param-name>
                <param-value>my_wsgi_module.my_handler_class().handler_method</param-value>
            </init-param>
            -->
            <!--
            And this is the app_directory/app_filename/app_callable_name
            combo
            The defaults for these three variables are
            ""/application.py/handler
            So if you specify no values at all for any of app_* variables,
            then modjy
            will by default look for "handler" in "application.py" in the
            servlet
            context root.
            <init-param>
                <param-name>app_directory</param-name>
                <param-value>some_sub_directory</param-value>
            </init-param>
            -->
            <init-param>
                <param-name>app_filename</param-name>
                <param-value>demo_app.py</param-value>
            </init-param>
            <!--
            Supply a value for this parameter if you want your application
            callable to have a different name than the default.
            <init-param>
                <param-name>app_callable_name</param-name>
                <param-value>my_handler_func</param-value>
            </init-param>
            -->
            <!-- Do you want application callables to be cached? -->
            <init-param>
                <param-name>cache_callables</param-name>
                <param-value>1</param-value>
            </init-param>
            <!-- Should the application be reloaded if it's .py file changes?
            -->
            <!-- Does not work with the app_import_name mechanism -->
            <init-param>
                <param-name>reload_on_mod</param-name>
                <param-value>1</param-value>
            </init-param>
            <init-param>
                <param-name>log_level</param-name>
                <param-value>debug</param-value>
                <!-- <param-value>info</param-value> -->
                <!-- <param-value>warn</param-value> -->
                <!-- <param-value>error</param-value> -->
                <!-- <param-value>fatal</param-value> -->
            </init-param>
            <load-on-startup>1</load-on-startup>
        </servlet>
        
        <servlet-mapping>
            <servlet-name>modjy</servlet-name>
        <url-pattern>/*</url-pattern>
        </servlet-mapping>
    </web-app>



The demo_app should be coded as shown in Listing 13-12. As part of
the WSGI standard, the application provides a function that the
server calls for each request. In this case, that function is named
*handler*. The function must take two parameters, the first being a
dictionary of CGI-defined environment variables. The second is a
callback that returns the HTTP headers. The callback function
should also be called as follows
*start_response(status, response_headers, exx_info=None)*, where
status is an HTTP status, response_headers is a list of HTTP
headers, and exc_info is for exception handling. Let’s take a look
at the *demo_app.py* application and identify the features we’ve
just discussed.

*Listing 13-12.*
::
    
    import sys
    import string
    
    def escape_html(s):
        return s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
    
    def cutoff(s, n=100):
        if len(s) > n: return s[:n]+ '.. cut ..'
        return s
    
    def handler(environ, start_response):
        writer = start_response("200 OK", [ ('content-type', 'text/html') ])
        response_parts = '''<html><head>
            <title>Modjy demo WSGI application running on Local Server!</title>
            </head>
            <body>
            <p>Modjy servlet running correctly:
            jython $version on $platform:
            </p>
            <h3>Hello jython WSGI on your local server!</h3>
            <h4>Here are the contents of the WSGI environment</h4>'''
        environ_str = "<table border='1'>"
        keys = environ.keys()
        keys.sort()
        for ix, name in enumerate(keys):
            if ix % 2:
                background='#ffffff'
            else:
                background='#eeeeee'
            style = " style='background-color:%s;'" % background
            value = escape_html(cutoff(str(environ[name]))) or '&#160;'
            environ_str = "%s\\n<tr><td%s>%s</td><td%s>%s</td></tr>" % \\
                (environ_str, style, name, style, value)
        environ_str = "%s\\n</table>" % environ_str
        response_parts = response_parts + environ_str + '</body></html>\\n'
        response_text = string.Template(response_parts)
        return [response_text.substitute(version=sys.version, platform=sys.platform)]


This application returns the environment configuration for the
server on which you run the application. As you can see, the page
is quite simple to code and really resembles a servlet.

Once the application has been set up and configured, simply compile
the code into a WAR file and deploy it to the Java servlet
container of your choice. In this case, we used Glassfish V2 and it
worked nicely. However, this same application should be deployable
to Tomcat, JBoss, or the like.

Summary
=======

There are various ways that we can use Jython for creating simple
web-based applications. Jython servlets are a good way to make
content available on the web, and you can also utilize them along
with a JSP page which allows for a Model-View-Controller situation.
This is a good technique to use for developing sophisticated web
applications, especially those mixing some JavaScript into the
action because it really helps to organize things. Most Java web
applications use frameworks or other techniques in order to help
organize applications in such a way as to apply the MVC concept. It
is great to have a way to do such work with Jython as well.

This chapter also discussed creation of WSGI applications in Jython
making use of modjy. This is a good low-level way to generate web
applications as well, although modjy and WSGI are usually used for
implementing web frameworks and the like. Solutions such as Django
use WSGI in order to follow the standard put forth for all Python
web frameworks with PEP 333. You can see from the section in this
chapter that WSGI is also a nice quick way to write web
applications, much like writing a servlet in Jython.

In the next chapters, you will learn more about using web
frameworks available to Jython, specifically Django and Pylons.
These two frameworks can make any web developers life much easier,
and now that they are available on the Java platform via Jython
they are even more powerful. Using a templating technique such as
Django can be really productive and it is a good way to design a
full-blown web application. Techniques discussed in this chapter
can also be used for developing large web applications, but using a
standard framework such as those discussed in the following chapter
should be considered. There are many great ways to code Jython web
applications today, and the options continue to grow!