001/*
002 * JGrapes Event Driven Framework
003 * Copyright (C) 2016,2018  Michael N. Lipp
004 *
005 * This program is free software; you can redistribute it and/or modify it 
006 * under the terms of the GNU Affero General Public License as published by 
007 * the Free Software Foundation; either version 3 of the License, or 
008 * (at your option) any later version.
009 *
010 * This program is distributed in the hope that it will be useful, but 
011 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
012 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License 
013 * for more details.
014 *
015 * You should have received a copy of the GNU Affero General Public License along 
016 * with this program; if not, see <http://www.gnu.org/licenses/>.
017 */
018
019package org.jgrapes.osgi.demo.upnp;
020
021import java.io.InputStream;
022import java.net.InetSocketAddress;
023import java.net.URI;
024import java.security.KeyStore;
025import java.security.SecureRandom;
026import java.util.Arrays;
027import java.util.Collections;
028import javax.net.ssl.KeyManagerFactory;
029import javax.net.ssl.SSLContext;
030import org.jgrapes.core.Channel;
031import org.jgrapes.core.Component;
032import org.jgrapes.core.Components;
033import org.jgrapes.core.NamedChannel;
034import org.jgrapes.core.events.Stop;
035import org.jgrapes.http.HttpServer;
036import org.jgrapes.http.InMemorySessionManager;
037import org.jgrapes.http.LanguageSelector;
038import org.jgrapes.http.events.Request;
039import org.jgrapes.io.FileStorage;
040import org.jgrapes.io.NioDispatcher;
041import org.jgrapes.io.util.PermitsPool;
042import org.jgrapes.net.SslCodec;
043import org.jgrapes.net.TcpServer;
044import org.jgrapes.osgi.core.ComponentCollector;
045import org.jgrapes.webconsole.base.BrowserLocalBackedKVStore;
046import org.jgrapes.webconsole.base.ConletComponentFactory;
047import org.jgrapes.webconsole.base.ConsoleWeblet;
048import org.jgrapes.webconsole.base.KVStoreBasedConsolePolicy;
049import org.jgrapes.webconsole.base.PageResourceProviderFactory;
050import org.jgrapes.webconsole.base.WebConsole;
051import org.jgrapes.webconsole.vuejs.VueJsConsoleWeblet;
052import org.osgi.framework.BundleActivator;
053import org.osgi.framework.BundleContext;
054
055/**
056 *
057 */
058public class Application extends Component implements BundleActivator {
059
060    private static BundleContext context;
061    private Application app;
062
063    /**
064     * Returns the context passed to the application.
065     *
066     * @return the bundle context
067     */
068    public static BundleContext context() {
069        return context;
070    }
071
072    /*
073     * (non-Javadoc)
074     * 
075     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.
076     * BundleContext)
077     */
078    @Override
079    public void start(BundleContext context) throws Exception {
080        Application.context = context;
081        // The demo component is the application
082        app = new Application();
083        // Attach a general nio dispatcher
084        app.attach(new NioDispatcher());
085
086        // Create TLS "converter"
087        KeyStore serverStore = KeyStore.getInstance("JKS");
088        try (InputStream storeData
089            = Application.class.getResourceAsStream("/localhost.jks")) {
090            serverStore.load(storeData, "nopass".toCharArray());
091        }
092        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
093            KeyManagerFactory.getDefaultAlgorithm());
094        kmf.init(serverStore, "nopass".toCharArray());
095        SSLContext sslContext = SSLContext.getInstance("TLS");
096        sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
097        // Create a TCP server for SSL
098        Channel securedNetwork = app.attach(
099            new TcpServer().setServerAddress(new InetSocketAddress(7443))
100                .setBacklog(3000).setConnectionLimiter(new PermitsPool(50)));
101        // Network level unencrypted channel.
102        Channel httpTransport = new NamedChannel("httpTransport");
103        app.attach(new SslCodec(httpTransport, securedNetwork, sslContext));
104
105        // Create an HTTP server as converter between transport and application
106        // layer.
107        app.attach(new HttpServer(app,
108            httpTransport, Request.In.Get.class, Request.In.Post.class));
109
110        // Build application layer
111        app.attach(new InMemorySessionManager(app.channel()));
112        app.attach(new LanguageSelector(app.channel()));
113        app.attach(new FileStorage(app.channel(), 65536));
114        ConsoleWeblet consoleWeblet
115            = app.attach(new VueJsConsoleWeblet(app.channel(), Channel.SELF,
116                new URI("/portal/")))
117                .prependClassTemplateLoader(getClass())
118                .prependConsoleResourceProvider(getClass())
119                .prependResourceBundleProvider(getClass());
120        WebConsole console = consoleWeblet.console();
121        console.attach(new BrowserLocalBackedKVStore(
122            console, consoleWeblet.prefix().getPath()));
123        console.attach(new KVStoreBasedConsolePolicy(console));
124        console.attach(new NewConsoleSessionPolicy(console));
125        console.attach(new ComponentCollector<>(
126            console, context, PageResourceProviderFactory.class,
127            type -> {
128                switch (type) {
129                case "org.jgrapes.webconsole.provider.gridstack.GridstackProvider":
130                    return Arrays.asList(
131                        Components.mapOf("configuration", "CoreWithJQueryUI"));
132                default:
133                    return Arrays.asList(Collections.emptyMap());
134                }
135            }));
136        console.attach(new ComponentCollector<>(
137            console, context, ConletComponentFactory.class));
138        Components.start(app);
139
140//              context().addServiceListener(new RootDeviceListener(),
141//                "(&" + "("+Constants.OBJECTCLASS 
142//                              + "=" + UPnPDevice.class.getName() + ")"
143//                       + "("+UPnPDevice.UDN+"=*)" + ")");
144//              
145//              ServiceReference[] roots = null;
146//              roots = context().getServiceReferences(
147//                              UPnPDevice.class.getName(),
148//                              "(&" + "("+Constants.OBJECTCLASS 
149//                                              + "=" + UPnPDevice.class.getName() + ")"
150//                                       + "("+UPnPDevice.UDN+"=*)" + ")");
151//              roots = null;
152    }
153
154    /*
155     * (non-Javadoc)
156     * 
157     * @see
158     * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
159     */
160    @Override
161    public void stop(BundleContext context) throws Exception {
162        app.fire(new Stop(), Channel.BROADCAST);
163        Components.awaitExhaustion();
164    }
165
166    /**
167     * The main method.
168     *
169     * @param args command line arguments
170     * @throws Exception the exception
171     */
172    @SuppressWarnings("PMD.SignatureDeclareThrowsException")
173    public static void main(String[] args) throws Exception {
174        new Application().start(null);
175    }
176
177}