Since we're on a major migration process of this website, some component documents here are out of sync right now. In the meantime you may want to look at the early version of the new website
https://camel.apache.org/staging/
We would very much like to receive any feedback on the new site, please join the discussion on the Camel user mailing list.
IntroductionThe focus of this Tutorial is to introduce you how you can create, design a simple SOA solution using Camel and OSGI. Most of the current and commercial SOA solutions rely on standards XML/WSDL/BPMN/BPEL and Business Processes (designed through WYSIWYG editor like Eclipse or propriatary product) which are deployed and orchestrated into a Business Process Expression Language engine. Such a solution can be envisaged for big companies because the skills/time to market are important or when different development standards exist inside the company like (Java, .NET). In the 90's, such developments have been made using CORBA or COM+/DCOM Microsoft technology. But both approaches had (and still have) significant problems and limitations. Complexity is a big issue. Any of the data that is passed requires very specific formatting, and many of the rules for programming are simply too difficult to follow without encountering errors. Even at the height of their popularity, CORBA was used primarily in large system development staffed by legions of programmers, while COM was used, often reluctantly, by teams of Microsoft developers. Open Standards Gateway Initiative provides a Java-based platform for integrating both Java and non-Java application components. This technology provides the standardized functions for constructing applications from small, individual components and deploying them as a single application. The core component of OSGi is the OSGi Framework. The OSGi Framework is a very specific class-loading model. In addition to its normal Java execution environment, this framework incorporates an OSGi modules layer that adds private classes for modules and allows for controlled linking between modules. The OSGi Framework also includes life-cycle management for starting, stopping, adding and removing modules, as well as a service registry for sharing objects between modules. Coupling the OSGI framework with a lightweight Enterprise Service Bus will allow you easily to design the routing between your different modules. A module can be a Plain Old Java Object (POJO), a Web Service designed with Apache CXF framework, a component like an ordering system. In fact, the module or bundle which is the term used by OSGI represent the level of granularity that you identify for your application. In this first part of the OSGI tutorial, we will show you how to:
The second part of this tutorial will be derived from the Reporting incident tutorial and will show you how a more real application (which is web based) can be re-scoped into a OSGI application. Tutorial is not up-to-date This tutorial was written when Camel 2.0 was just released and uses the frameworks and libraries of that time. PrerequisitesThis tutorial uses:
Note: The sample project can be downloaded, see the resources section. Step 1 : Initial Project SetupFirst, we create two eclipse projects using the maven archetype 'pax:create-bundle'. This archetype is helpful because it generates a pom.xml file that we will use with maven goal(s) to create the:
PAX Project More info about the PAX maven plugin can be found here. PAX project does not include only maven but also tools to run, debug and deploy web application. We will address them in the second part of the tutorial and particularly the web integration To create the simple service project, execute the following command in your Unix/Dos console. mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=demo.service -DbundleGroupId=demo.service -DbundleName=demo.service-bundle -Dversion=0.1 Remark:
To allow your project to be imported in Eclipse, execute the following command in the directory demo.service-bundle. mvn org.ops4j:maven-pax-plugin:eclipse To create the Camel project, execute the following command mvn org.ops4j:maven-pax-plugin:create-bundle -Dpackage=demo.camel -DbundleGroupId=demo.camel -DbundleName=demo.camel-bundle -Dversion=0.1 cd demo.camel-bundle mvn org.ops4j:maven-pax-plugin:eclipse Two folders are created with the following name:
Next, you import these projects into your favorite workspace of Eclipse. Step 2 : Develop the interfaceDeveloping an OSGI project could be 'potentially' time consuming regarding to:
You could figure out that developing OSGI is similar to develop EJB components using EJB 1.0 specification. Remember that time when the only way to design an enterprise solution was to use EJB with its proxy, stub-skeleton classes, the protocol RMI/IIOP (blocked by most of the firewall) for the communication between the client and the server, ... and so on and so on Luckily, this is not the case because the specification has tried to avoid such pitfalls and interesting projects exist today to simplify our life:
The goals of these frameworks are to:
Although this tutorial is based on Spring Dynamic Modules. Remark : The OSGI specification v4R2 has been published recently and contain the Blueprint Container specification - RFC 124. So now, it is time to create the interface that we will use in this project. Open Eclipse environment if not already done and create a new folder "service" in TransformService.java package demo.service; public interface TransformService { public Object transform(Object obj); } Step 3 : Create the class implementing the interfaceNext, we will create the class TransformServiceImpl.java package demo.service.impl; import java.util.Date; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; public class TransformServiceImpl implements TransformService { private static final transient Log LOG = LogFactory.getLog(TransformServiceImpl.class); private boolean verbose = true; private String prefix = "MyTransform"; public Object transform(Object body) { String answer = prefix + " set body: " + new Date(); if (verbose) { System.out.println(">> call >> " + answer); } LOG.info(">> call >>" + answer); return answer; } public boolean isVerbose() { return verbose; } public void setVerbose(boolean verbose) { this.verbose = verbose; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } } Step 4 : Create the spring configuration filesThe next step concerns the creation of the configuration files who will allow to inject dependency and later the deployment of the bundle into the OSGI server and its registration as a 'service'. a) Dependency Injection Create the file demo-service-bundle-contxt.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <!-- regular spring configuration file defining the beans for this bundle. The configuration of OSGi definitions is kept in a separate configuration file so that this file can easily be used for integration testing outside of an OSGi environment --> <bean id="transformService" class="demo.service.impl.TransformServiceImpl"> </bean> </beans> b) OSGI 'Injection' Create the file demo-service-bundle-contxt-osgi.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <osgi:service ref="transformService"> <osgi:interfaces> <value>demo.service.TransformService</value> </osgi:interfaces> </osgi:service> </beans> The xml tag osgi:service will help to register our OSGI service top of the OSGI server and will publish the interfaces as available for another bundles who would like to use them. Remark: for more information about Spring Dynamic Modules and configuration, I recommend to read its documentation and of course the OSGI R4v2 specification integrating 'blueprint container' Spring configuration files Two XML files have been created to work with Spring beans and Spring OSGI beans separately (as proposed by spring - section D.1 Generated Project Features at-a-glance) but you can also merge the content in one file. Step 5 : Generate the jar of the bundleNow, that the code and the configuration files are ready, we will use maven to generate the Remark : We use maven to avoid to create manually the MANIFEST file. Before to execute the command, the pom.xml file must be modified like this : pom demo.service-bundle <?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <properties> <bundle.symbolicName>demo.service-bundle</bundle.symbolicName> <bundle.namespace>demo.service</bundle.namespace> <commons.log>1.1</commons.log> </properties> <modelVersion>4.0.0</modelVersion> <groupId>demo.service</groupId> <artifactId>demo.service-bundle</artifactId> <version>0.1</version> <name>${bundle.symbolicName} [${bundle.namespace}]</name> <packaging>bundle</packaging> <build> <resources> <resource> <directory>src/main/resources</directory> </resource> <!-- | example additional resource entries, useful when building Eclipse RCP applications --> <resource> <directory>.</directory> <includes> <include>plugin.xml</include> <include>plugin.properties</include> <include>icons/**</include> </includes> </resource> </resources> <plugins> <plugin> <groupId>org.ops4j</groupId> <artifactId>maven-pax-plugin</artifactId> <version>1.4</version> <!-- | enable improved OSGi compilation support for the bundle life-cycle. | to switch back to the standard bundle life-cycle, move this setting | down to the maven-bundle-plugin section --> <extensions>true</extensions> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>1.4.3</version> <!-- | the following instructions build a simple set of public/private classes into an OSGi bundle --> <configuration> <instructions> <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName> <Bundle-Version>${pom.version}</Bundle-Version> <Export-Package>${bundle.namespace};version="${pom.version}"</Export-Package> <Private-Package>${bundle.namespace}.impl.*</Private-Package> <Include-Resource>src/main/resources</Include-Resource> </instructions> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi_R4_core</artifactId> <version>1.0</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi_R4_compendium</artifactId> <version>1.0</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging-api</artifactId> <version>${commons.log}</version> <scope>provided</scope> </dependency> </dependencies> </project> This command can be launched from Eclipse (if you have integrated maven within Eclipse (eclipse maven plugin)) or a Unix/Dos prompt in the folder where your pom.xml file is located: mvn clean install org.ops4j:maven-pax-plugin:eclipse If this command does not report any error, then a 'MANIFEST.MF' file containing the following information is created in the folder 'META-INF' and Manifest-Version: 1.0 Export-Package: demo.service;version="0.1" Private-Package: demo.service.impl Built-By: Charlesm Build-Jdk: 1.6.0_07 Bundle-Version: 0.1.0 Tool: Bnd-0.0.255 Bundle-Name: Demo Service Bundle Bnd-LastModified: 1228122578185 Created-By: Apache Maven Bundle Plugin Bundle-ManifestVersion: 2 Bundle-SymbolicName: demo.demo.service-bundle Import-Package: demo.service;version="0.1",org.apache.commons.logging bnd tool This file is created because the POM.file contains the maven felix plugin which uses the tool bnd. Bnd stands for BuNDle tool and has been created by Peter Kriens (OSGi Technical Officer) Step 6 : Create the Camel context file and OSGI dependencyThe next step is quite simple for Camel users because we will create two configurations files, one containing the routing and the other with a reference to our TransformationService deployed in a OSGI bundle.
CamelContext.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.0.0.xsd"> <camelContext xmlns="http://camel.apache.org/schema/spring"> <route> <from uri="timer://myTimer?fixedRate=true&period=10000"/> <bean ref="myTransform" method="transform"/> <to uri="log:ExampleRouter"/> </route> </camelContext> </beans> The routing defined here is a timer which will trigger every 10th second and call the POJO 'MyTransform' and send the result to the 'camel:log' component. As, you can see, this is a pure Camel configuration file without any reference to an OSGI bundle
bundle-context-osgi.xml <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:osgi="http://www.springframework.org/schema/osgi" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/osgi http://www.springframework.org/schema/osgi/spring-osgi.xsd"> <osgi:reference id="myTransform" interface="demo.service.TransformService"/> </beans> Remarks:
Step 7 : Generate the manifest and jar filePrior to run/launch the command generating the MANIFEST file, you must modify the pom.xml file in order to allow the OSGI bundle to import/use the services classes : demo.service pom demo.camel-bundle <?xml version="1.0" encoding="UTF-8"?> <project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> <properties> <bundle.symbolicName>demo.camel-bundle</bundle.symbolicName> <bundle.namespace>demo.camel</bundle.namespace> </properties> <modelVersion>4.0.0</modelVersion> <groupId>demo.camel</groupId> <artifactId>demo.camel-bundle</artifactId> <version>0.1</version> <name>${bundle.symbolicName} [${bundle.namespace}]</name> <packaging>bundle</packaging> <build> <resources> <resource> <directory>src/main/resources</directory> </resource> <!-- | example additional resource entries, useful when building Eclipse RCP applications --> <resource> <directory>.</directory> <includes> <include>plugin.xml</include> <include>plugin.properties</include> <include>icons/**</include> <include>META-INF/*</include> </includes> </resource> </resources> <plugins> <plugin> <groupId>org.ops4j</groupId> <artifactId>maven-pax-plugin</artifactId> <version>1.4</version> <!-- | enable improved OSGi compilation support for the bundle life-cycle. | to switch back to the standard bundle life-cycle, move this setting | down to the maven-bundle-plugin section --> <extensions>true</extensions> </plugin> <plugin> <groupId>org.apache.felix</groupId> <artifactId>maven-bundle-plugin</artifactId> <version>1.4.3</version> <!-- | the following instructions build a simple set of public/private classes into an OSGi bundle --> <configuration> <instructions> <Bundle-SymbolicName>${bundle.symbolicName}</Bundle-SymbolicName> <Bundle-Version>${pom.version}</Bundle-Version> <Import-Package>demo.service;version="${pom.version}"</Import-Package> <Include-Resource>src/main/resources</Include-Resource> </instructions> </configuration> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi_R4_core</artifactId> <version>1.0</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>org.osgi</groupId> <artifactId>osgi_R4_compendium</artifactId> <version>1.0</version> <scope>provided</scope> <optional>true</optional> </dependency> <dependency> <groupId>demo.service</groupId> <artifactId>demo.service-bundle</artifactId> <version>${pom.version}</version> </dependency> </dependencies> </project> Run the command and check that the MANIFEST file created looks like the following : Manifest-Version: 1.0 Bundle-Version: 0.1 Build-Jdk: 1.6.0_16 Built-By: Charlesm Tool: Bnd-0.0.255 Bnd-LastModified: 1256906516718 Bundle-Name: demo.camel-bundle [demo.camel] Bundle-ManifestVersion: 2 Created-By: Apache Maven Bundle Plugin Import-Package: demo.service;version="0.1" Bundle-SymbolicName: demo.camel-bundle The most important point that we see in this file is that we will import the package demo.service allowing Camel mediation router to have access to the service Transform exposed as an OSGI service by the bundle demo.service. Step 8 : Deploy the bundlesWe will show you now that we can easily deploy our bundles in two OSGI servers running a different OSGI kernel:
Apache Felix KarafAs mentioned in the documentation, Apache Felix Karaf is a small OSGi based runtime which provides a lightweight container onto which various components and applications can be deployed. Moreover, the server provides administration, security, logging and provisioning features who will help you during the deployment and administration steps. Here is the list of features provided by the osgi server :
If this is not yet done, download Apache Felix Karaf 1.0.0 server and install it. Launch the server by executing the command in the c:\apache-felix-karaf-1.0.0\bin>karaf If this is the first time that Karaf is started, then you will see that a new data folder is created under the root folder. This folder will contain the bundles installed at the startup of the server In order to allow our bundles (demo.service and demo.camel) to work with Apache Camel framework, execute the following commands to download and install the 'Camel and Spring bundles': 1. Add camel feature file karaf@root> features:addUrl mvn:org.apache.camel.karaf/features/2.0.0/xml/features This new feature file contains the list of camel bundles to be installed. This will avoid that you install each required bundle (= jar) separately though the command osgi:install 2. Install bundles using feature command karaf@root> features:install spring karaf@root> features:install spring-dm karaf@root> features:install camel-core karaf@root> features:install camel-spring karaf@root> features:install camel-osgi Verify that your list of bundles is complete using command osgi:list karaf@root> osgi:list START LEVEL 100 ID State Blueprint Level Name [ 0] [Active ] [ ] [ 0] System Bundle (2.0.0) [ 1] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell Various Commands (1.0.0) [ 2] [Active ] [ ] [ 30] Apache MINA Core (2.0.0.M6) [ 3] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell PackageAdmin Commands (1.0.0) [ 4] [Active ] [Created ] [ 30] Apache Felix Karaf :: JAAS Modules (1.0.0) [ 5] [Active ] [Created ] [ 30] Apache Felix Karaf :: JAAS Config (1.0.0) [ 6] [Active ] [Created ] [ 30] Apache Felix Karaf :: Blueprint Deployer (1.0.0) [ 7] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell Admin (1.0.0) [ 8] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell Log Commands (1.0.0) [ 9] [Active ] [Created ] [ 30] Apache Felix Karaf :: Features Command (1.0.0) [ 10] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell SSH (1.0.0) [ 11] [Active ] [ ] [ 30] Apache Mina SSHD :: Core (0.2.0) [ 12] [Active ] [ ] [ 30] Apache Felix Gogo Shell Runtime (0.2.0) [ 13] [Active ] [Created ] [ 30] Apache Felix Karaf :: Features Core (1.0.0) [ 14] [Active ] [Created ] [ 30] Apache Felix Karaf :: Management (1.0.0) [ 15] [Active ] [ ] [ 30] org.osgi.impl.bundle.jmx (4.2.0.200907080519) [ 16] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell Console (1.0.0) [ 17] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell OSGi Commands (1.0.0) [ 18] [Active ] [Created ] [ 30] Apache Felix Karaf :: Features Management (1.0.0) [ 19] [Active ] [Created ] [ 30] Apache Felix Karaf :: Spring Deployer (1.0.0) [ 20] [Active ] [Created ] [ 30] Apache Felix Karaf :: Features Deployer (1.0.0) [ 21] [Active ] [Created ] [ 30] Apache Felix Karaf :: Shell ConfigAdmin Commands (1.0.0) [ 22] [Active ] [ ] [ 10] Apache Felix File Install (2.0.0) [ 23] [Active ] [ ] [ 10] Apache Felix Prefrences Service (1.0.2) [ 24] [Active ] [ ] [ 10] Apache Felix Configuration Admin Service (1.2.4) [ 25] [Active ] [ ] [ 8] OPS4J Pax Logging - API (1.4) [ 26] [Active ] [ ] [ 8] OPS4J Pax Logging - Service (1.4) [ 27] [Active ] [ ] [ 5] OPS4J Pax Url - mvn: (1.0.0) [ 28] [Active ] [ ] [ 5] OPS4J Pax Url - wrap: (1.0.0) [ 29] [Active ] [Created ] [ 20] Apache Geronimo Blueprint Bundle (1.0.0) [ 32] [Active ] [ ] [ 60] Apache ServiceMix Bundles: aopalliance-1.0 (1.0.0.1) [ 33] [Active ] [ ] [ 60] Spring Core (2.5.6.SEC01) [ 34] [Active ] [ ] [ 60] Spring Beans (2.5.6.SEC01) [ 35] [Active ] [ ] [ 60] Spring AOP (2.5.6.SEC01) [ 36] [Active ] [ ] [ 60] Spring Context (2.5.6.SEC01) [ 37] [Active ] [ ] [ 60] Spring Context Support (2.5.6.SEC01) [ 38] [Active ] [ ] [ 60] Apache ServiceMix Bundles: cglib-2.1_3 (2.1.0.3_2) [ 39] [Active ] [ ] [ 60] spring-osgi-io (1.2.0) [ 40] [Active ] [ ] [ 60] spring-osgi-core (1.2.0) [ 41] [Active ] [ ] [ 60] spring-osgi-extender (1.2.0) [ 42] [Active ] [ ] [ 60] spring-osgi-annotation (1.2.0) [ 43] [Active ] [ ] [ 60] Java Activation API (1.1.1) [ 44] [Active ] [ ] [ 60] Apache ServiceMix Specs :: JAXB API 2.1 (1.3.0) [ 45] [Active ] [ ] [ 60] Apache ServiceMix Specs :: STAX API 1.0 (1.3.0) [ 46] [Active ] [ ] [ 60] Apache ServiceMix Bundles: jaxb-impl-2.1.6 (2.1.6.1) [ 47] [Active ] [ ] [ 60] camel-core (2.0.0) [ 48] [Active ] [ ] [ 60] geronimo-jta_1.1_spec (1.1.1) [ 49] [Active ] [ ] [ 60] Spring AOP (2.5.6) [ 50] [Active ] [ ] [ 60] Spring Beans (2.5.6) [ 51] [Active ] [ ] [ 60] Spring Core (2.5.6) [ 52] [Active ] [ ] [ 60] Spring Context (2.5.6) [ 53] [Active ] [ ] [ 60] Spring Transaction (2.5.6) [ 54] [Active ] [ ] [ 60] camel-spring (2.0.0) [ 55] [Active ] [ ] [ 60] camel-osgi (2.0.0) Next, copy the our two jar into the OR install them using the command : servicemix> osgi:install \-s mvn:demo.service/demo.service-bundle/0.1 servicemix> osgi:install \-s mvn:demo.camel/demo.camel-bundle/0.1 After a few seconds, you should see on the Karaf log console the following text: >> call >> MyTransform set body: Mon Dec 01 11:02:28 CET 2008 Remarks :
Spring DM serverSpring DM server compare to ServiceMix Kernel, Eclipse Equinox or Apache Felix is much more than a OSGI server. This is a completely module-based Java application server that is designed to run enterprise Java applications and Spring-powered applications with a new degree of flexibility and reliability. It offers a simple yet comprehensive platform to develop, deploy, and service enterprise Java applications. We have decided to it inside this tutorial not only because we have designed spring-based applications but because we are convince that OSGI platform will become the next standard for the Web Application Server. Existing Commercial and open-source are gradually migrating their servers to support OSGI. Like ServiceMix Kernel, start the Spring DM server by launching the following command in your Unix/Dos environement : c:\springsource-dm-server-1.0.0.RELEASE\bin>startup When the server is started, open your favorite browser and point to the following url
When the bundles are uploaded, the screen is refreshed and shows a list of the deployed applications like this :
To verify that the Camel service bundle works perfectly, open the trace.log file located in the folder : c:\springsource-dm-server-1.0.0.RELEASE\serviceability\trace\demo.demo.camel-bundle-0.1\trace.log and you should see the following text [2008-12-02 10:43:19.500] edRate=true&period=10000 System.out I >> call >> MyTransform set body: ... [2008-12-02 10:43:19.500] edRate=true&period=10000 demo.service.TransformServiceImpl.unknown I >> call >>MyTransform set body: ... [2008-12-02 10:43:19.500] edRate=true&period=10000 ExampleRouter.unknown I Exchange[BodyType:String, Body:MyTransform set body: ... ConclusionWell, we have finished the first part of the tutorial. Even if the example is simple, we have introduced very important concepts and show you how to design a small SOA solution, package it and deploy it under two different OSGI servers. I'm really sure that in a near future a maven plugin will be created to facilitate this task and will automate the deployment within your favorite OSGI servers. Links
#Resources |