summaryrefslogblamecommitdiffstats
path: root/dozentenmodul/src/main/java/org/openslx/dozmod/App.java
blob: b64ad0b8bdc56220197f3425ab238e982d5f0528 (plain) (tree)
1
2
3
4
5
6
7
8
9
                           
 



                                       
                                     
                    
                           
                                                   
                        
                         
                        
                     
                                           

                               
 
                                
                                  
                              
                             
 
                                         
                                          
                                     

                                   

                                      
                                         
                                           
                                  
                                         
                                          
                                              
                                                 
                                             
                                                 
                                              
                                
                             
 


                                        

                  


                                                                         





                                                                  


                                                                         
 

                                                      
                                                 
 
                                       
                                                                                                                      





                                                                      
                                                                              
                                                 
                                                          
                                                 
                                               
                                                                                                                     





                                                     
                                                                                                     
                                                
                                                     
                                         
                                                                                                 
                                    
                 
 

















                                                                                                             


                                                                                         


                                                                      
                                                       
                                                                                               








                                                                                                                                
                                                  
                                                


                                   







                                                                                                                                 














                                                                
                 
                     
                                      
                                       

                                                                                                                    


                               
                                                             

                                                                                                                            
 
                                     
                                              

                                                                        


                                                                                  



                                                                                  

                                                                                  

                         
 


                                                
                





                                                                                                 
                                                                                                       
                                                                                                    
                         
                                        





                                                                                                                                                
                                 




                                                                                                                                      

                         
 



                                                                        
                                   
                                                        
 
                                                     
                                  
                         



                                                          
                                                               
                        
                                                                 


                                               

                                             
                                                

                                                              
                                      


                                                                 

                                                               
                                 



                                               

                      

                             
                                                                                   
                                                           
                                                                                                         
                                                      
                                                                             

                                                           
                                                                                                                                               

                                                                                                        

                                                                       

                                         

                                                                                                  
                         
                 



                                                                                                  
 
                                                                                     


                                                           
                                                                                                                          

                                                                                              





                                                                                                                                      


                                                                                                                                         

                                         
                                                  

                         
         
 



                                                                     
                                                                                                       


                 


                                                                     
                                                              






                                                                                        
                                               


                                                                                        
                                                                      


                                                                                                       

                                                                                                                                           


                                                                                                                                 

                                                               
                                                                                                      
                                                                                          

                                                                                                                                             




                                                                                  



                                                                                                            




























                                                                                          




                                                                                

                                          

                               
                                           

                                                  
         
 
























                                                                                          
                                                         
                                     
         



                                                                    
 
package org.openslx.dozmod;

import java.awt.AWTEvent;
import java.awt.Font;
import java.awt.Toolkit;
import java.awt.event.AWTEventListener;
import java.awt.event.ContainerEvent;
import java.io.File;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Locale;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.net.ssl.SSLContext;
import javax.swing.SwingUtilities;
import javax.swing.UIDefaults;
import javax.swing.UIManager;

import org.apache.log4j.AppenderSkeleton;
import org.apache.log4j.BasicConfigurator;
import org.apache.log4j.FileAppender;
import org.apache.log4j.Level;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PatternLayout;
import org.apache.log4j.spi.LoggingEvent;
import org.openslx.dozmod.Config.ProxyMode;
import org.openslx.dozmod.gui.Gui;
import org.openslx.dozmod.gui.MainWindow;
import org.openslx.dozmod.gui.helper.I18n;
import org.openslx.dozmod.gui.helper.Language;
import org.openslx.dozmod.gui.helper.MessageType;
import org.openslx.dozmod.util.ClientVersion;
import org.openslx.dozmod.util.ProxyConfigurator;
import org.openslx.thrifthelper.ThriftManager;
import org.openslx.util.AppUtil;
import org.openslx.util.Util;

import com.formdev.flatlaf.FlatDarkLaf;
import com.formdev.flatlaf.FlatLightLaf;

public class App {

	// Logger
	private final static Logger LOGGER = Logger.getLogger(App.class);

	public static final int THRIFT_PORT = 9090;

	public static final int THRIFT_SSL_PORT = THRIFT_PORT + 1;

	public static final int THRIFT_TIMEOUT_MS = 15000;

	private static CountDownLatch proxyLatch = new CountDownLatch(1);
	
	private static boolean proxyInitDone = false;

	private static String masterServerHost = null;

	private static String setupFileLogger() {

		// path to the log file
		final String logFilePath = Config.getPath() + File.separator + Branding.getConfigDirectory() + ".log";

		// check if we had an old log file
		final File logFile = new File(logFilePath);
		if (logFile.exists() && !logFile.isDirectory()) {
			// we have one, rename it to 'bwSuite.log.old'
			try {
				File oldFile = new File(logFilePath + ".old");
				oldFile.delete();
				logFile.renameTo(oldFile);
				logFile.delete();
			} catch (Exception e) {
				LOGGER.error("Could not move '" + logFilePath + "' to '" + logFilePath + ".old'", e);
			}
		}

		// add file appender to global logger
		FileAppender fa = null;
		try {
			fa = new FileAppender(new PatternLayout("[%t] %-5p %F - %m%n"), logFilePath);
			fa.setEncoding("UTF-8");
			fa.setThreshold(Level.DEBUG);
		} catch (IOException e) {
			LOGGER.error("Failed to set logfile path to '" + logFilePath + "': ", e);
			return null;
		}

		final FileAppender ffa = fa;
		final Pattern re = Pattern.compile("authorization:(\\w|\\+|/|\\s)+", Pattern.CASE_INSENSITIVE
				| Pattern.MULTILINE);

		AppenderSkeleton ap = new AppenderSkeleton() {

			@Override
			public boolean requiresLayout() {
				return ffa.requiresLayout();
			}

			@Override
			public void close() {
				ffa.close();
			}

			@Override
			protected void append(LoggingEvent event) {
				// TODO Set up filtering properly
				if ("org.apache.http.wire".equals(event.getLoggerName()))
					return;
				String s = event.getRenderedMessage();
				if (s.contains("uthorization")) {
					Matcher m = re.matcher(s);
					if (m.find()) {
						s = m.replaceAll("Authorization: ***********");
					}
				}
				ffa.append(new LoggingEvent(event.getFQNOfLoggerClass(), event.getLogger(),
						event.getTimeStamp(), event.getLevel(), s, event.getThreadName(),
						event.getThrowableInformation(), event.getNDC(), event.getLocationInformation(),
						event.getProperties()));
			}
		};

		// register file logger (appender)
		BasicConfigurator.configure(ap);

		return logFilePath;
	}
	
	public static void main(final String[] args) throws InvocationTargetException, InterruptedException
	{
		// setup basic logging appender to log output on console if no external appender (log4j.properties) is configured
		if (LogManager.getRootLogger().getAllAppenders() == null) {
			BasicConfigurator.configure();
		}
		
		if (args.length >= 2) {
			if (args[0].equals("--json")) {
				writeJsonUpdateFile(args[1]);
				return;
			}
			if (args[0].equals("--dump")) {
				Branding.dump(args[1]);
				return;
			}
		}
		if (args.length >= 3) {
			if (args[0].equals("--pack")) {
				Branding.pack(args[1], args[2]);
				return;
			}
		}
		try {
			Config.init();
		} catch (Exception e) {
			Gui.showMessageBox(null, I18n.APP.getString("App.Message.error.loadingConfigurationFailed"),
					MessageType.ERROR, LOGGER, e);
			return;
		}

		final String logFilePath = setupFileLogger();
		AppUtil.logHeader(LOGGER, Branding.getApplicationName(), App.class.getPackage().getImplementationVersion());
		LOGGER.info("Starting logging to " + logFilePath);

		// Setting the locale
		if (!setPreferredLanguage()) {
			// Detect operating system language
			String ul = System.getProperty("user.language");
			if (ul.equals("de")) {
				Locale.setDefault(new Locale("de", "DE"));
				Config.setPreferredLanguage(Language.DE_DE.value);
			} else if (ul.equals("tr")) {
				Locale.setDefault(new Locale("tr", "TR"));
				Config.setPreferredLanguage(Language.TR_TR.value);
			} else {
				Locale.setDefault(new Locale("en", "US"));
				Config.setPreferredLanguage(Language.EN_US.value);
			}
		}

		// Install FlatLaf look and feel
		FlatLightLaf.installLafInfo();
		FlatDarkLaf.installLafInfo();
		
		try {
			if (System.getProperty("swing.defaultlaf") != null) {
				UIManager.setLookAndFeel(System.getProperty("swing.defaultlaf"));
			} else if(Config.getLookAndFeel() != null) {
					UIManager.setLookAndFeel(Config.getLookAndFeel());
			} else {
				UIManager.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
				Config.setLookAndFeel("com.sun.java.swing.plaf.gtk.GTKLookAndFeel");
			}
		} catch (Throwable e1) {
			try {
				LOGGER.error("Something went wrong with the chosen 'LookAndFeel'. Falling back to default 'SystemLookAndFeel'");
				UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

				if(Config.getLookAndFeel() == null) {
					Config.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
				}
			} catch (Throwable e) {
				LOGGER.error("Cannot select system look and feel", e);
				LOGGER.error("----------------------------------");
				LOGGER.error("Cannot initialize GUI. Make sure you have the non-headless version of Java installed.");
				System.exit(1);
			}
		}

		// Setup swing style
		System.setProperty("awt.useSystemAAFontSettings", "on");
		System.setProperty("swing.aatext", "true");

		// Adjust font size
		adjustFontSize(Config.getFontScaling());

		// Set up connection to master server
		final String host;
		int port;
		boolean useSsl;
		if (args.length == 3) {
			host = args[0];
			port = Util.parseInt(args[1], -1);
			useSsl = Boolean.parseBoolean(args[2]);
		} else {
			host = Branding.getMasterServerAddress();
			port = THRIFT_SSL_PORT;
			useSsl = true;
		}
		// remember masterserver host
		masterServerHost = host;
		// now start the proxy detection
		if (Config.getProxyMode() == ProxyMode.AUTO) {
			// Initialize the proxy settings
			new Thread() {
				@Override
				public void run() {
					ProxyConfigurator.init();
					proxyInitDone = true;
					proxyLatch.countDown();
				}
			}.start();
		} else {
			proxyInitDone = true;
			proxyLatch.countDown();
		}
		// SSL
		if (useSsl) {
			try {
				SSLContext ctx = SSLContext.getInstance("TLSv1.2");
				ctx.init(null, null, null);
				ThriftManager.setMasterServerAddress(ctx, host, port, THRIFT_TIMEOUT_MS);
			} catch (final Exception e1) {
				SwingUtilities.invokeAndWait(new Runnable() {
					@Override
					public void run() {
						boolean ret = Gui.showMessageBox(null, I18n.APP.getString("App.Message.yesNo.SSLNotAvailable"),
								MessageType.QUESTION_YESNO, LOGGER, e1);
						if (!ret) {
							System.exit(1);
						}
					}
				});
				useSsl = false;
				port = port - 1; // This assumes SSL port is always plain port + 1
			}
		}
		// No "else", might be fallback for failed SSL
		if (!useSsl) {
			ThriftManager.setMasterServerAddress(null, host, port, THRIFT_TIMEOUT_MS);
		}

		// Setup global thrift connection error handler and then open the GUI
		SwingUtilities.invokeLater(new Runnable() {
			@Override
			public void run() {
				Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
					@Override
					public void uncaughtException(Thread t, Throwable e) {
						if (e instanceof ClassCastException) {
							// HACK HACK: Endless chains of exceptions from nowhere on Linux after suspend
							// (seems to be driver/version/model specific)
							if (e.getMessage().contains("SurfaceData"))
								return;
						}
						Gui.showMessageBox(null,
								I18n.APP.getString("App.Message.warning.uncaughtException", t.getName()),
								MessageType.WARNING, LOGGER, e);
					}
				});
				MainWindow.open();
			}
		});
	}

	private static void writeJsonUpdateFile(String destination) {
		try {
			ClientVersion.createJson(destination);
		} catch (IOException e) {
			LOGGER.error("Failed to write JSON update file to '" + destination + "': ", e);
		}
	}

	private static void adjustFontSize(int percent) {
		if (percent == 100 || percent <= 0 || percent > 1000)
			return;
		final float scaling = 0.01f * (float) percent;
		int size = determineDefaultFontSize(UIManager.getLookAndFeelDefaults());
		if (size == -1) {
			size = determineDefaultFontSize(UIManager.getDefaults());
		}
		if (size == -1) {
			size = 12;
		}
		final float defaultSize = size;
		Toolkit.getDefaultToolkit().addAWTEventListener(new AWTEventListener() {
			@Override
			public void eventDispatched(AWTEvent event) {
				if (event instanceof ContainerEvent) {
					ContainerEvent containerEvent = (ContainerEvent) event;
					if (containerEvent.getID() == ContainerEvent.COMPONENT_ADDED) {
						Font font = containerEvent.getChild().getFont();
						// Do not update font in tables and ComboBoxes on every renderer call to prevent weirdness.
						// This prevents multiple instances of fonts being scaled multiple times.
						if (containerEvent.getChild().getName() != null && 
							(containerEvent.getChild().getName().toLowerCase().contains("render") || 
							(containerEvent.getChild().getName().toLowerCase().contains("combo")))){
							return;
						}
						if (font != null && font.getSize2D() <= defaultSize) {
							containerEvent.getChild().setFont(
									new Font(font.getName(), font.getStyle(), Math.round(font.getSize2D()
											* scaling)));
						}
					}
				}
			}
		}, AWTEvent.COMPONENT_EVENT_MASK | AWTEvent.CONTAINER_EVENT_MASK);
		Font tbFont = UIManager.getFont("TitledBorder.font");
		if (tbFont != null) {
			UIManager.put("TitledBorder.font", tbFont.deriveFont(tbFont.getSize2D() * scaling));
		}
	}

	private static int determineDefaultFontSize(UIDefaults defaults) {
		if (defaults == null)
			return -1;
		int sizes[] = new int[100];
		Set<Object> keys = new HashSet<>(defaults.keySet());
		for (Object key : keys) {
			if (key == null)
				continue;
			Object value = defaults.get(key);
			if (value == null)
				continue;
			if (value instanceof Font) {
				Font font = (Font) value;
				if (font.getSize() > 0 && font.getSize() < sizes.length) {
					sizes[font.getSize()]++;
				}
			}
		}
		int best = -1;
		for (int index = 0; index < sizes.length; ++index) {
			if (best == -1 || sizes[best] < sizes[index]) {
				best = index;
			}
		}
		return sizes[best];
	}

	/**
	 * Blocks as long as initialization is still going on. Currently this is
	 * just the proxy setup, so this should be used before any network
	 * communication happens.
	 */
	public static void waitForInit() {
		if (proxyInitDone)
			return;
		try {
			proxyLatch.await();
		} catch (InterruptedException e) {
		}
	}

	/**
	 * Check if any default language is already set and valid.
	 * @return true, if any default language exists and is valid.
	 */
	private static boolean setPreferredLanguage() {
		// Check if any preferred language exists
		String language = Config.getPreferredLanguage();
		// Check whether the provided string is null or empty
		if (language == null || language.trim().isEmpty()) {
			return false;
		}
		// Check if the provided string has the format language_country e.g. en_US
		String[] parts = language.split("_");
		if (parts.length != 2) {
			return false;
		}
		Locale locale = new Locale(parts[0], parts[1]);
		// Check now if the locale is valid
		if (!Arrays.asList(Locale.getAvailableLocales()).contains(locale)) {
			return false;
		}
		Locale.setDefault(locale);
		return true;
	}

	public static synchronized boolean isInitDone() {
		return proxyInitDone;
	}

	public static synchronized String getMasterServerAddress() {
		return masterServerHost;
	}
}