001/**
002 * Copyright (C) 2014  Universidade de Aveiro, DETI/IEETA, Bioinformatics Group - http://bioinformatics.ua.pt/
003 *
004 * This file is part of Dicoogle/dicoogle.
005 *
006 * Dicoogle/dicoogle is free software: you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation, either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * Dicoogle/dicoogle is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with Dicoogle.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package pt.ua.dicoogle;
020
021import org.dcm4che2.data.TransferSyntax;
022import org.slf4j.Logger;
023import org.slf4j.LoggerFactory;
024import org.xml.sax.SAXException;
025import pt.ua.dicoogle.DicomLog.LogDICOM;
026import pt.ua.dicoogle.DicomLog.LogXML;
027import pt.ua.dicoogle.core.*;
028import pt.ua.dicoogle.plugins.PluginController;
029import pt.ua.dicoogle.rGUI.client.windows.ConnectWindow;
030import pt.ua.dicoogle.sdk.Utils.Platform;
031import pt.ua.dicoogle.sdk.utils.TagsStruct;
032
033
034import javax.swing.*;
035import java.awt.*;
036import java.io.File;
037import java.io.FileNotFoundException;
038import java.io.IOException;
039import java.net.InetAddress;
040import java.net.SocketException;
041import java.net.URI;
042import java.net.UnknownHostException;
043import java.util.*;
044
045/**
046 * Main class for Dicoogle
047 * @author Filipe Freitas
048 * @author Luís A. Bastião Silva <bastiao@ua.pt>
049 * @author Samuel Campos <samuelcampos@ua.pt>
050 * @author Eduardo Pinho <eduardopinho@ua.pt>
051 */
052public class Main
053{
054    private static final Logger logger = LoggerFactory.getLogger(Main.class);
055
056    private static boolean optimizeMemory = true;
057    private static boolean isGUIServer = false;
058    //indicates whether the client and the server were pulled at the same time
059    private static boolean isFixedClient = false;
060    private static int remoteGUIPort = 0;
061    public static boolean MAC_OS_X = (System.getProperty("os.name").toLowerCase().startsWith("mac os x"));
062    /**
063     * Generate a random integer number between 0 and 100
064     *
065     * This is used to verify if the RMI client is in the same
066     * process as the RMI server.
067     * The client as 1/1000 probability to hit the correct number
068     * if it is not in the same process.
069     */
070    public static int randomInteger = (new Random()).nextInt(1001);
071
072    /**
073     * Starts the graphical user interface for Dicoogle
074     * @param args the command line arguments
075     */
076    public static void main(String[] args)
077    {
078        //System.setProperty("log4j.configurationFile", "log4j-2.xml");
079        //PropertyConfigurator.configure("log4j.properties");
080        if (Platform.getMode() == Platform.MODE.BUNDLE)
081        {
082            File homeDir = new File(Platform.homePath());
083            if (!homeDir.exists())
084            {
085                homeDir.mkdir();
086            }
087        }
088        
089        if (args.length == 0)
090        {
091            isFixedClient = true;
092
093            LaunchDicoogle();
094            LaunchWebApplication();
095        } else {
096
097            if (args[0].equals("-v"))
098            {
099                isFixedClient = true;
100                //DebugManager.getInstance().setDebug(true);
101                LaunchDicoogle();
102                //DebugManager.getInstance().debug("Starting Client Thread");
103                LaunchWebApplication();
104            }
105            if (args[0].equals("-s"))
106            {
107                LaunchDicoogle();
108            } else if (args[0].equals("-g") || args[0].equals("--gui"))
109            {
110                LaunchDicoogle();
111                LaunchGUIClient();
112            } else if (args[0].equals("-c"))
113            {
114                LaunchGUIClient();
115            }
116            else if (args[0].equals("-w") || args[0].equals("--web") || args[0].equals("--webapp")) {
117                // open browser
118                LaunchDicoogle();
119                LaunchWebApplication();
120            }
121            else if (args[0].equals("-h") || args[0].equals("--h") || args[0].equals("-help") || args[0].equals("--help"))
122            {
123                System.out.println("Dicoogle PACS: help");
124                System.out.println("-s : Start the server");
125                System.out.println("-w : Start the server and load web application in default browser (default)");
126                System.out.println("-g : [deprecated] Start the server and run the desktop client application");
127                System.out.println("-c : [deprecated] Run the desktop client application");
128            }
129            else
130            {
131                System.out.println("Wrong arguments!");
132            }
133        }
134        /** Register System Exceptions Hook */
135        ExceptionHandler.registerExceptionHandler();
136
137        optimizeMemoryUsage();
138    }
139
140    /**
141     * This function creates a TimerTask to periodically run Garbage Colector
142     *
143     */
144    private static void optimizeMemoryUsage()
145    {
146        if (optimizeMemory)
147        {
148            class FreeMemoryTask extends TimerTask
149            {
150
151                @Override
152                public void run()
153                {
154                    Runtime.getRuntime().gc();
155                    System.out.println("\nFree Memory: " + Runtime.getRuntime().freeMemory() / 1024 / 1024
156                            + "\nTotal Memory: " + Runtime.getRuntime().totalMemory() / 1024 / 1024
157                            + "\nMax Memory: " + Runtime.getRuntime().maxMemory() / 1024 / 1024);
158                }
159            }
160
161            //FreeMemoryTask freeMemTask = new FreeMemoryTask();
162            //Timer timer = new Timer();
163            //timer.schedule(freeMemTask, 5000, 5000);
164        }
165    }
166    
167    public static boolean LaunchWebApplication() {
168        if (!Desktop.isDesktopSupported() || !Desktop.getDesktop().isSupported(Desktop.Action.BROWSE)) {
169            logger.warn("Desktop browsing is not supported in this machine! "
170                    + "Request to open web application ignored.");
171            return false;
172        } else {
173            try {
174                ServerSettings settings = ServerSettings.getInstance();
175                URI uri = URI.create("http://localhost:" + settings.getWeb().getServerPort());
176                Desktop.getDesktop().browse(uri);
177                return true;
178            } catch (IOException ex) {
179                logger.warn("Request to open web application ignored", ex);
180                return false;
181            }
182        }
183    }
184
185    public static void LaunchDicoogle()
186    {
187        try
188        {
189            //System.out.println("\n"+addressString(localAddresses()) + "\n");
190            System.setProperty("java.rmi.server.hostname", addressString(localAddresses()));
191        } catch (SocketException ex) {
192            logger.warn(ex.getMessage(), ex);
193        }
194        
195        logger.debug("Starting Dicoogle");
196        /* This logic will be not neccessary. This should be sent to the Plugins.
197        try
198        {
199            Anonymous.getInstance().start();
200        } catch(Exception e) {
201            logger.warn("Could not start Anonimize service", e);
202        }*/
203        
204        
205        logger.debug("Loading configuration file: {}", Platform.homePath());
206        
207        /* Load all Server Settings from XML */
208        ServerSettings settings = new XMLSupport().getXML();
209
210        try
211        {
212            TagsStruct _tags = new TagsXML().getXML();
213
214            //load DICOM Services Log
215            LogDICOM ll = new LogXML().getXML();
216
217        } catch (SAXException | IOException ex) {
218            logger.error(ex.getMessage(), ex);
219        }
220
221        /***
222         * Connect to P2P
223         */
224        /** Verify if it have a defined node */
225        if (!settings.isNodeNameDefined())
226        {
227            String hostname = "Dicoogle";
228
229            try
230            {
231                InetAddress addr = InetAddress.getLocalHost();
232
233                // Get hostname
234                hostname = addr.getHostName();
235            } catch (UnknownHostException e)
236            {
237            }
238
239            String response = (String) JOptionPane.showInputDialog(null,
240                    "What is the name of the machine?",
241                    "Enter Node name",
242                    JOptionPane.QUESTION_MESSAGE, null, null,
243                    hostname);
244
245            settings.setNodeName(response);
246            settings.setNodeNameDefined(true);
247
248            // Save Settings in XML
249            XMLSupport _xml = new XMLSupport();
250            _xml.printXML();
251        }
252
253        logger.debug("Name: {}", ServerSettings.getInstance().getNodeName());
254        
255        TransferSyntax.add(new TransferSyntax("1.2.826.0.1.3680043.2.682.1.40", false,false, false, true));
256        TransferSyntax.add(new TransferSyntax("1.2.840.10008.1.2.4.70", true,false, false, true));
257        TransferSyntax.add(new TransferSyntax("1.2.840.10008.1.2.5.50", false,false, false, true));    
258
259        PluginController PController = PluginController.getInstance();
260
261        // Start the Inicial Services of Dicoogle
262        pt.ua.dicoogle.server.ControlServices.getInstance();
263
264        // Lauch Async Index 
265        // It monitors a folder, and when a file is touched an event
266        // triggers and index is updated.
267        if (ServerSettings.getInstance().isMonitorWatcher()) {
268            AsyncIndex asyncIndex = new AsyncIndex();
269        }
270        //Signals that this application is GUI Server
271        isGUIServer = true;
272
273        //GUIServer GUIserv = new GUIServer();
274    }
275
276    @Deprecated
277    private static void LaunchGUIClient()
278    {
279
280        /* Load all Client Settings from XML */
281        ClientSettings settings = new XMLClientSupport().getXML();
282
283        if (isGUIServer)
284        {
285            remoteGUIPort = ServerSettings.getInstance().getRemoteGUIPort();
286
287            RunClient rc = new RunClient();
288            rc.run();
289        } else
290        {
291            ConnectWindow.getInstance();
292        }
293
294    }
295
296    public static boolean isFixedClient()
297    {
298        return isFixedClient;
299    }
300
301    public static int getRemoteGUIPort()
302    {
303        return remoteGUIPort;
304    }
305
306    private static Set<InetAddress> localAddresses() throws SocketException
307    {
308        Set<InetAddress> localAddrs = new HashSet<>();
309
310        /*Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
311
312        while (ifaces.hasMoreElements()) {
313        NetworkInterface iface = ifaces.nextElement();
314        Enumeration<InetAddress> addrs = iface.getInetAddresses();
315        while (addrs.hasMoreElements())
316        localAddrs.add(addrs.nextElement());
317        }
318         *
319         */
320        InetAddress in;
321        try
322        {
323            in = InetAddress.getLocalHost();
324            InetAddress[] all = InetAddress.getAllByName(in.getHostName());
325            localAddrs.addAll(Arrays.asList(all));
326
327        } catch (UnknownHostException ex)
328        {
329            logger.error(ex.getMessage(), ex);
330        }
331
332        return localAddrs;
333    }
334
335    /**
336     *
337     * @param addrs
338     * @return
339     */
340    private static String addressString(Collection<InetAddress> addrs)
341    {
342        String s = "";
343        for (InetAddress addr : addrs)
344        {
345            if (addr.isLoopbackAddress())
346            {
347                continue;
348            }
349            if (s.length() > 0)
350            {
351                s += "!";
352            }
353            s += addr.getHostAddress();
354        }
355        return s;
356    }
357
358    private static class RunClient implements Runnable
359    {
360
361        @Override
362        public void run()
363        {
364            ConnectWindow.getInstance();
365        }
366    }
367}