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.console;
020
021import de.mnl.osgi.lf4osgi.Logger;
022import de.mnl.osgi.lf4osgi.LoggerFactory;
023import java.io.InputStream;
024import java.net.InetSocketAddress;
025import java.net.URI;
026import java.net.URISyntaxException;
027import java.security.KeyStore;
028import java.security.SecureRandom;
029import java.util.Arrays;
030import java.util.Collections;
031import javax.net.ssl.KeyManagerFactory;
032import javax.net.ssl.SSLContext;
033import org.jgrapes.core.Channel;
034import org.jgrapes.core.Component;
035import org.jgrapes.core.Components;
036import org.jgrapes.core.NamedChannel;
037import org.jgrapes.core.events.Stop;
038import org.jgrapes.http.HttpServer;
039import org.jgrapes.http.InMemorySessionManager;
040import org.jgrapes.http.LanguageSelector;
041import org.jgrapes.http.events.Request;
042import org.jgrapes.io.FileStorage;
043import org.jgrapes.io.NioDispatcher;
044import org.jgrapes.io.util.PermitsPool;
045import org.jgrapes.net.SslCodec;
046import org.jgrapes.net.TcpServer;
047import org.jgrapes.osgi.core.ComponentCollector;
048import org.jgrapes.webconsole.base.BrowserLocalBackedKVStore;
049import org.jgrapes.webconsole.base.ConletComponentFactory;
050import org.jgrapes.webconsole.base.ConsoleWeblet;
051import org.jgrapes.webconsole.base.KVStoreBasedConsolePolicy;
052import org.jgrapes.webconsole.base.PageResourceProviderFactory;
053import org.jgrapes.webconsole.base.WebConsole;
054import org.jgrapes.webconsole.bootstrap4.Bootstrap4Weblet;
055import org.jgrapes.webconsole.jqueryui.JQueryUiWeblet;
056import org.osgi.framework.BundleActivator;
057import org.osgi.framework.BundleContext;
058
059/**
060 *
061 */
062public class Application extends Component implements BundleActivator {
063
064    private static Logger LOG = LoggerFactory.getLogger(Application.class);
065    private static BundleContext context;
066    private Application app;
067
068    /**
069     * Returns the context passed to the application.
070     *
071     * @return the bundle context
072     */
073    public static BundleContext context() {
074        return context;
075    }
076
077    /*
078     * (non-Javadoc)
079     * 
080     * @see org.osgi.framework.BundleActivator#start(org.osgi.framework.
081     * BundleContext)
082     */
083    @Override
084    @SuppressWarnings("PMD.DataflowAnomalyAnalysis")
085    public void start(BundleContext context) throws Exception {
086        Application.context = context;
087        // The demo component is the application
088        app = new Application();
089        // Attach a general nio dispatcher
090        app.attach(new NioDispatcher());
091
092        // Create TLS "converter"
093        KeyStore serverStore = KeyStore.getInstance("JKS");
094        try (InputStream storeData
095            = Application.class.getResourceAsStream("/localhost.jks")) {
096            serverStore.load(storeData, "nopass".toCharArray());
097        }
098        KeyManagerFactory kmf = KeyManagerFactory.getInstance(
099            KeyManagerFactory.getDefaultAlgorithm());
100        kmf.init(serverStore, "nopass".toCharArray());
101        SSLContext sslContext = SSLContext.getInstance("TLS");
102        sslContext.init(kmf.getKeyManagers(), null, new SecureRandom());
103        // Create a TCP server for SSL
104        Channel securedNetwork = app.attach(
105            new TcpServer().setServerAddress(new InetSocketAddress(6443))
106                .setBacklog(3000).setConnectionLimiter(new PermitsPool(50)));
107        // Network level unencrypted channel.
108        Channel httpTransport = new NamedChannel("httpTransport");
109        app.attach(new SslCodec(httpTransport, securedNetwork, sslContext));
110
111        // Create an HTTP server as converter between transport and application
112        // layer.
113        app.attach(new HttpServer(app,
114            httpTransport, Request.In.Get.class, Request.In.Post.class));
115
116        // Build application layer
117        app.attach(new InMemorySessionManager(app.channel()));
118        app.attach(new LanguageSelector(app.channel()));
119        app.attach(new FileStorage(app.channel(), 65536));
120
121        createJQueryUiConsole(context);
122        createBootstrap4Console(context);
123        createVueJsConsole(context);
124        Components.start(app);
125        LOG.info("Application started.");
126    }
127
128    private void createJQueryUiConsole(BundleContext context)
129            throws URISyntaxException {
130        ConsoleWeblet consoleWeblet
131            = app.attach(new JQueryUiWeblet(app.channel(), Channel.SELF,
132                new URI("/jqconsole/")))
133                .prependResourceBundleProvider(getClass());
134        WebConsole console = consoleWeblet.console();
135        console.attach(new BrowserLocalBackedKVStore(
136            console, consoleWeblet.prefix().getPath()));
137        console.attach(new KVStoreBasedConsolePolicy(console));
138        console.attach(new NewConsoleSessionPolicy(console));
139        console.attach(new ComponentCollector<>(
140            console, context, PageResourceProviderFactory.class,
141            type -> {
142                switch (type) {
143                case "org.jgrapes.webconsole.provider.gridstack.GridstackProvider":
144                    return Arrays.asList(
145                        Components.mapOf("configuration",
146                            "CoreWithJQUiPlugin"));
147                default:
148                    return Arrays.asList(Collections.emptyMap());
149                }
150            }));
151        console.attach(new ComponentCollector<>(
152            console, context, ConletComponentFactory.class));
153    }
154
155    private void createBootstrap4Console(BundleContext context)
156            throws URISyntaxException {
157        ConsoleWeblet consoleWeblet
158            = app.attach(new Bootstrap4Weblet(app.channel(), Channel.SELF,
159                new URI("/b4console/")));
160        WebConsole console = consoleWeblet.console();
161        console.attach(new BrowserLocalBackedKVStore(
162            console, consoleWeblet.prefix().getPath()));
163        console.attach(new KVStoreBasedConsolePolicy(console));
164        console.attach(new NewConsoleSessionPolicy(console));
165        console.attach(new ComponentCollector<>(
166            console, context, PageResourceProviderFactory.class,
167            type -> {
168                switch (type) {
169                case "org.jgrapes.webconsole.provider.gridstack.GridstackProvider":
170                    return Arrays.asList(
171                        Components.mapOf("configuration",
172                            "CoreWithJQUiPlugin"));
173                default:
174                    return Arrays.asList(Collections.emptyMap());
175                }
176            }));
177        console.attach(new ComponentCollector<>(
178            console, context, ConletComponentFactory.class));
179    }
180
181    private void createVueJsConsole(BundleContext context)
182            throws URISyntaxException {
183        ConsoleWeblet consoleWeblet
184            = app.attach(new DemoConsoleWeblet(app.channel(), Channel.SELF,
185                new URI("/vjconsole/")));
186        WebConsole console = consoleWeblet.console();
187        console.attach(new BrowserLocalBackedKVStore(
188            console, consoleWeblet.prefix().getPath()));
189        console.attach(new KVStoreBasedConsolePolicy(console));
190        console.attach(new NewConsoleSessionPolicy(console));
191        console.attach(new ComponentCollector<>(
192            console, context, PageResourceProviderFactory.class,
193            type -> {
194                switch (type) {
195                case "org.jgrapes.webconsole.provider.gridstack.GridstackProvider":
196                    return Arrays.asList(
197                        Components.mapOf("configuration",
198                            "CoreWithJQUiPlugin"));
199                default:
200                    return Arrays.asList(Collections.emptyMap());
201                }
202            }));
203        console.attach(new ComponentCollector<>(
204            console, context, ConletComponentFactory.class));
205    }
206
207    /*
208     * (non-Javadoc)
209     * 
210     * @see
211     * org.osgi.framework.BundleActivator#stop(org.osgi.framework.BundleContext)
212     */
213    @Override
214    public void stop(BundleContext context) throws Exception {
215        app.fire(new Stop(), Channel.BROADCAST);
216        Components.awaitExhaustion();
217    }
218}