Skip navigation.

exploreopera

| Help

Sign up | Help

Web Applications Blog

avatar

Slides from EuroPython08

, , , ...

Now that I'm settled home and recovered from the great Vilnius Mojitos it's time to get the slides online before people start complaining ;-)

During the course of the conference I gave 2 presentations

Spring into Pylons

This was a talk on the experience we've had while working on widgets.opera.com

Slides can be found here

Capistrano for Pylons Deployment

This was a talk on how we've found a tool for deploying Ruby on Rails projects useful for deploying out Pylons based widgets.opera.com

Slides can be found here

If you think that you fit on a team that works with the kind of things described in the slides above, then let us know because we're hiring!
avatar

Opera Widgets SDK Beta launched!

, , , ...

With the release of the beta version of the Opera Widgets SDK, developers can get started on making widgets for mobile. So far UIQ 3.3 supports widgets, and support on more platforms are on the way. The SDK contains among other things:

Documentation
We added 10 more articles and documentation about widgets, especially focusing on mobile and cross device development. See the SDK overview page for more information.
Tools
The new Widget emulator will emulate how your widget will work on different devices. And it's implemented as a widget! You can also use Opera Dragonfly to debug your widget, even when they are running in the emulator.
Libraries
You'll find several libraries on the Libraries section on dev.opera.com which helps speed up development. This list will expand as we go forward.

And it's all on the web! Each article and tool is available from Opera's developer website dev.opera.com.

Widget emulator and Dragonfly

The Widget emulator is a tool for seeing how your widgets will look like and behave on different devices. It emulates screen size, media query behavior, the docked widget mode as well as aspects such as network speed and the size of the preference store.

Development for mobile is made quicker and easier by not having to transfer the widget to test on the actual device. Instead, you can just reload your widget in the emulator and test on the phone when you're happy with the resuts.

By using Opera Dragonfly, you can also debug your widgets. They show up as runtimes just like the webpages in your tabs.

Widgets on mobile and cross device development

Opera Mobile 9.5 is on it's way, and with it, developers will be able to make widgets on mobile phones. Mobile widgets offer interesting possibilities for people on the move, as well as challenges when it comes to usability and performance.

For now, we've put up an overview of the characteristics of widgets on mobile phones and some advice for doing cross device development. There's also some advice for a mobile development process. With these, and the emulator, you can get a head start in developing for mobile.

What the future holds

We have more in the works for extending the SDK with more useful tools and documentation. Some examples:

More libraries
More libraries are in the works. For example, we have a library for internationalization and localization coming up and there is also a framework for more easily making resizable and flexible widget in the works.
More functionality in the emulator
We're working on simpler ways of loading your widget into the emulator, as well as emulating more of the functionality of widgets.
More widget examples
We're going to give you a few more widgets to play with, in addition to those you can already find on widgets.opera.com.
More documentation and articles
We'll improve on the current documents, as well as adding more articles. Examples include converting widgets from other runtimes to Opera widgets, more guidelines for mobiles, using Dragonfly with widgets and more.

We also want to hear what you have to say, so do visit the Opera Widgets forums and tells us what you need!

avatar

widgets.opera.com team coming to EuroPython

, , ,

Just a quick shout out to the community. We've just had the flights confirmed for our attendance of EuroPython 2008 in Vilnius this summer. If I get my act together on it, I'm hoping to also give a talk on our experiences with the widgets.opera.com project.

I hope to see some of you there!
avatar

Search engine friendly multi-language support on widgets.opera.com

, , , ...

What, why and how

We have just released a new version of widgets.opera.com where we have reworked our multi-language solution to support search engines. Instead of storing the user selected language in a cookie, which hides all languages except the default from search engines and indexers, we now have unique URLs for every language which the site is translated into.

In this blog post we present both the important client-side effects, and our technical Python and Pylons-based solutions on the servers. So if you are a user of widgets.opera.com, a developer who wants a similar site structure, or just passing by - read on!

Read more...

avatar

widgets.opera.com 2.0 - the best place for you to share and find Opera Widgets

, , , ...

It's a been a while since we unleashed widgets.opera.com 2.0 on the world so we're long overdue a blog post from the devs regarding what we have done and where we intend to take things.

Read more...

avatar

Who can make the best travel widget?

, ,

As you may have seen over on the Widgets blog, Opera is running a new Widget competition. This time, we're looking for something useful to the harried and weary traveler. And remember, Opera Mobile 9 features Widget suppport - just the sort of thing the for the business person on the go.

What you can win:
Let's face it, a competition is only as good as its prizes.

First place grand prize: Windows Mobile handheld - running Opera, of course.

Second place: Nintnedo DS - with the Opera browser, naturally.

(5) Third place prizes: Opera goodie bags with t-shirts, pins, stickers, etc - unfortunately without an Opera browser, obviously. Although I know where you can get one for free chuck norris.

We're also giving away an early-bird prize to reward the ultra-diligent among you. The best widget submitted a week ahead of the deadline will win another Nintendo DS Lite - with the Opera browser for DS, clearly.

Editors note: The following section(s) have been shamelessly stolen from the original Widgets post. Any and all plagarism is intentional and done without any shred of dignity. :devil:

Adjudication:

After the submission deadline, our experts will judge the submitted widgets on quality, usefulness, and the number of times it is downloaded. So be sure to promote your widget to make sure it gets the downloads it deserves!

The winning widget (and other outstanding entries) will be publicized far and wide so it will be used by scores of grateful travelers.

To enter:

Simply upload a widget here: http://widgets.opera.com/upload/ and send me a private message telling me about it.

(Send private message to Lawmune)

If it gets posted on our New Widgets Page within a few days after submission, that means it has been entered into the competition.

Deadlines:

1. The early bird submission deadline is May 28th, midnight (your time).

On midnight of June 2nd, the judges will make note of how many times the submitted widgets have been downloaded, and the early bird winner will be announced on June 4th.

2. The regular submission deadline is June 4th, midnight (your time).

On midnight of June 9th, the judges will make note of how many times the submitted widgets have been downloaded, and the final winners will be announced on June 11th.
avatar

Scalable Server Sent Events

, , , ...

Poking through my newsreader I realised that it's been a long time since the Web Applications Team actually shared any real code samples with you guys, and I think it's about high time we fixed that.

Back in September last year Arve Bersvendsen (virtuelvis) introduced you to Event Streaming to Web Browsers along with a few primitive code samples to get you started.

Some of you, quite rightly, pointed out that with a regular apache configuration the concept of keeping open many long lived requests doesn't hold. Also many of you requested that we provide more detailed examples of code working with this. I hope that today's blog post will go some way to addressing both issues.

The Theory

First for the boring part, a quick discussion of how to tackle the issue of
scalability.

In a normal web application when a server receives a HTTP request, an operating system thread is allocated from a pool and it is not released until the whole request is complete. When using SSE the request does not complete until the user closes the html document that has requested the event stream, this means that while a user is using your application the thread that is dealing with the SSE request can not be returned to the pool to serve requests for other users even if the SSE channel is currently idle.

The solution to this problem is to, while there is no data to be written to the outbound socket, release the thread so that it can process another client's request. Most languages have a socket APIs that can be exploited to implement this kind of behaviour however it is only recently that this technology is being exploited fully by web server developers in response to the AJAX wave of technologies.

The Solution

As far as hosting sites on apache is concerned I have not yet found any solution for doing this in a scalable manner in "traditional" languages such as PHP.

In python is is reasonably easy to hack together your own HTTP server using asyncore or socketserver however I don't feel that everyone should be writing their own HTTP 1.1 implementation just to achieve a scalable solution. This is where I think twisted.web has a good shot at being an elegant solution. The python twisted framework is an event based networking layer that allows reasonably easy access to the networking techniques we need and twisted.web is a HTTP layer built on top of that. In fact the existing SSE based web chat is a sort of compromise here, the twisted framework was used for low level connectivity but we did write our own, very primitive HTTP layer on top of that. One thing I'm interested in doing this year is having a go at this myself but using the full twisted.web stack rather than writing my own HTTP implementation.

In the Java world (where my heart lies) I'm ashamed to say that each vendor appears to have gone their own way regarding how to implement threadless waiting. Tomcat 6 features the newCometProcessor interface (why oh why did they choose a name that tied it to Comet:doh:) whereas Jetty have implemented continuations in the server. For a more complete assessment of the options in the Java world, see Greg's blog article on the subject (he also has GWT related code samples if you look around.

After looking at the above options I find that I am in general agreement with Greg, and have decided to proceed with the rest of this blog article to show
how to implement an SSE service in Java running on Jetty using their continuation support to achieve scalability.

The Code

The first part of the process was to model the Events themselves. Using the DOM Level 3 Events Specification and the Web Applications 1.0 Draft I came up with the following two classes and also decided to make them responsible for serialising themselves to a format that can be pushed out onto the output stream.
public class ServerSentEvent implements Serializable
{
    /** DOM 3 Event namespace */
    private static final String DOM3_EVENTS_NAMESPACE =
            "http://www.w3.org/2001/xml-events";    
    private String type;    
    private String target;
    private Boolean bubbles;    
    private Boolean cancelable;    
    private String namespace;
    // *snip * The usual getters and setters
    
    protected void generateEventContent(StringBuffer sb) {}
    
    public final String toString()
    {
        // Provide default event properties
        StringBuffer sb = new StringBuffer("");
        sb.append("Event: ").append(type).append("\n");
        sb.append("Class: ").append(this.getClass().getSimpleName()).append(
                "\n");
        if (target != null)
        {
            sb.append("Target: ").append(target).append("\n");
        }
        if (bubbles != null)
        {
            sb.append("Bubbles: ")
            .append(bubbles.booleanValue() ? "Yes" : "No").append("\n");
        }
        if (cancelable != null)
        {
            sb.append("Cancelable: ").append(
                    cancelable.booleanValue() ? "Yes" : "No").append("\n");
        }
        if (namespace != null)
        {
            sb.append("Namespace: ").append(namespace).append("\n");
        }
        
        // Provide method for subclasses to provide more event info
        this.generateEventContent(sb);
        
        // Terminate the event with a blank line
        sb.append("\n");
        return sb.toString();
    }
}

public class RemoteEvent extends ServerSentEvent
{
    /** Namespace for remote events */
    private static final String REMOTE_EVENT_NAMESPACE =
            "uuid:755e2d2d-a836-4539-83f4-16b51156341f";
    
    private List<String> data = new ArrayList<String>();
    
    public RemoteEvent(String type)
    {
        super(type, REMOTE_EVENT_NAMESPACE);
    }
    
    public void addData(String data)
    {
        this.data.add(data);
    }
    
    protected void generateEventContent(StringBuffer sb)
    {
        super.generateEventContent(sb);
        for (String currentData : data)
        {
            sb.append("data: ").append(currentData).append("\n");
        }
    }
}
There are also a couple of interfaces defined for listening to and generatingserver sent events in a similar manner to how such event listeners are handled in swing.

Next we need to implement a class to represent a client connection to the system, this is where the real meat lies.
public class SSEClient implements ServerSentEventListener
{
    public SSEClient(HttpServletRequest request, HttpServletResponse response)
    throws IOException
    {
        continuation = ContinuationSupport.getContinuation(request, this);
        this.response = response;
        this.request = request;
        
        writeHeaders(this.response);
    }
    
    private void writeHeaders(HttpServletResponse response) throws IOException
    {
        // Set the necessary headers
        response.setContentType("application/x-dom-event-stream");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Cache-Control", "no-cache");
        response.setHeader("Transfer-Encoding", "Chunked");
        response.flushBuffer();
    }
    
    private void writeEvent(ServerSentEvent event) throws IOException
    {
        byte[] eventBytes = event.toString().getBytes();
        ServletOutputStream os = response.getOutputStream();
        os.println(Integer.toHexString(eventBytes.length));
        os.println(event.toString());
        os.println();
        os.flush();
        response.flushBuffer();
    }
    
    public void run()
    {
        try
        {
            // This outer while loop ensures correct operation when emulating
            // continuations i.e. not running in Jetty
            while (true)
            {
                synchronized (this)
                {
                    while (events.peek() != null)
                    {
                        log.debug("Found an event, writing it to the stream");
                        writeEvent(events.remove());
                    }
                }
                continuation.suspend(WAIT_TIME);
            }
        }
        catch (IOException e)
        {
            this.disconnect();
        }
    }
}
Finally we need a service class to manage the currently connected clients that can be called on by servlet code. This is so simple I'll let you poke at that in the download.

And that's it! My entire JavaSSE framework in ~400 lines of code.

Using this framework I have created a couple of very simple demo services that rely on no major libraries such as spring in order to keep them short and sweet. All of this is covered by a BSD style license.

They can be found in the zip file below along with a maven pom that will allow you to run the demo with the command
$ mvn jetty:run
JavaSSE.zip

The Results

The Hardware

In order to make this a sensible test I comandeered a couple of spare blade servers that I had left over from testing a previous project. Both have the following specification.

* 2 dual core 3.20GHz Xeon processors
* 3Gb RAM
* Debian Etch amd64 kernel

The Proceedure

In order to test out the scalability of this implementation I thought it would be sufficient to just throw apache bench at the SSE stream for the server time example in the package above. This gives very rough indications.

On the Jetty machine I placed a war file of the project in the jetty webapps
directory and fired up the server process with
$ java -XX:MaxPermSize=128m -Xmx3072M -jar start.jar
Then on the Apache bench machine I set up a bunch of requests with a command such as
$ ab -n 50000 -c 2000 -t 18000  http://jettyserver:8080/JavaSSE/ServerTime

The Results

Using apache bench I was able to step up the number of simultaneous connections to 4000 before I experienced any problems with the service. This is a huge improvement on the 200 you would get out of a standard servlet container on default configuration but still nothing stellar performance wise.

Note that these tests were done on a default configuration of Jetty and so by tweaking the config perhaps I can squeeze even more out of the container.

One final point, after running apache bench for about an hour the jetty process froze, my best explanation for this is that there is a memory leak somewhere in the application. I don't have enough time to investigate this now but I'm sure we could find a t-shirt for the first person that does.

Wrap Up

I'm hoping that I get to maintain my current workload and therefore can continue to post more technical articles. I have plans to make a beefed up version of the chat that was made before and perhaps I will get through this exercise with twisted.web. If anyone has any requests let me know in the comments.
avatar

Web Developer Chat: Håkon Wium Lie on the <video> tag

, ,

Some folks have been curious about a little project we cooked up over on Opera Labs: The <video> element.

One of the main provocateurs for the <video> tag is our very own CTO, Håkon Wium Lie. He'll join us on Wednesday at 5:00 PM CET (check the time where you are) over on #webapps to explain why we want to make video a "first class citizen on the Web." Please join us for this exciting chat.
avatar

Yay My.Opera Developers

Today has been an exciting day, and it will be even more exciting when the developers on My Opera turn from working hard to party hard! The new My Opera community was launched today, and left several people severely impressed, along with others who haven't decided what to comment yet :wink:

Now that the site is up and running we welcome all of you to join, explore, (photo)blog, share, discuss, upload photos, themes, etc. so we figured we'd let you air your thoughts over to Fred, Espen and Sverre. These guys, along with many others, have been working on the My Opera Community and have made it so great. They would now love to hear your thoughts (and share theirs) at 1700 CET today on irc://irc.opera.com/webapps

Be there!
avatar

Web Developer Chat: Jon von Tetzchner

, ,

You may have seen we're approaching the 1001st widget on widgets.opera.com. 1001 widgets is a milestone we want to celebrate properly with the readers of this blog. So we invited a special guest to our Web chat next week.

More than 11 years ago, Jon von Tetzchner and Geir Ivarsøy huddled in a darkened corner of Telenor to create what would become Opera. Fast forward to today and Opera is everywhere. That success is due in no small part to Jon and Geir's original vision to make Opera small and portable.

And now we're sitting down to chat with the main man himself. Please join us next Thursday, March 1st, at 5:00 PM CET (or whatever the time is where you are) over on #webapps.

See you there!