[Title] Add logger
authorho.namkoong <ho.namkoong@samsung.com>
Thu, 11 Apr 2013 10:59:00 +0000 (19:59 +0900)
committerho.namkoong <ho.namkoong@samsung.com>
Fri, 12 Apr 2013 04:12:34 +0000 (13:12 +0900)
[Type]
[Module]
[Priority]
[Jira#]
[Redmine#] 7571
[Problem]
[Cause]
[Solution]
[TestCase]

Change-Id: Ib91b3ad723a0d22b3247d1762f996a75314e2ba4

26 files changed:
org.tizen.common/.classpath
org.tizen.common/log4j.xml
org.tizen.common/plugin.xml
org.tizen.common/src/org/tizen/common/CommonPlugin.java
org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.java
org.tizen.common/src/org/tizen/common/ui/page/preference/Messages.properties
org.tizen.common/src/org/tizen/common/ui/page/preference/TizenBasePreferencePage.java
org.tizen.common/src/org/tizen/common/util/FileUtil.java
org.tizen.common/src/org/tizen/common/util/SWTUtil.java
org.tizen.common/src/org/tizen/common/util/ThreadLocalMap.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/EclipseAppender.java [moved from org.tizen.common/src/org/tizen/common/util/log/TizenLog4jAppender.java with 82% similarity]
org.tizen.common/src/org/tizen/common/util/log/FileAppender.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/GoogleAnalyticAppender.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/Level.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/Logger.java
org.tizen.common/src/org/tizen/common/util/log/LoggerConstants.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/Messages.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/TizenLog4Configurator.java [deleted file]
org.tizen.common/src/org/tizen/common/util/log/TizenLog4jConfigurator.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/UserLogger.java [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/messages.properties [new file with mode: 0644]
org.tizen.common/src/org/tizen/common/util/log/preference/Messages.java [deleted file]
org.tizen.common/src/org/tizen/common/util/log/preference/TizenLoggerPreferencePage.java [deleted file]
org.tizen.common/src/org/tizen/common/util/log/preference/messages.properties [deleted file]
org.tizen.common/test/src/org/tizen/common/util/log/FileAppenderTest.java [new file with mode: 0644]
org.tizen.common/test/src/org/tizen/common/util/log/GoogleAnalyticAppenderTest.java [new file with mode: 0644]

index aab2b5a..3bc4976 100755 (executable)
@@ -1,24 +1,24 @@
-<?xml version="1.0" encoding="UTF-8"?>\r
-<classpath>\r
-       <classpathentry exported="true" kind="lib" path="lib/commons-logging-1.1.1.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/commons-collections-3.2.1.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/commons-pool-1.6.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/commons-lang3-3.1.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/commons-io-2.4.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/freemarker.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/log4j-1.2.17.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/slf4j-api-1.6.4.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="lib/slf4j-log4j12-1.6.4.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="test/lib/junit-4.10.jar" sourcepath="test/lib/junit-4.10-src.jar"/>\r
-       <classpathentry kind="lib" path="test/lib/asm-4.0.jar"/>\r
-       <classpathentry kind="lib" path="test/lib/asm-tree-4.0.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="test/lib/javassist-3.16.1-GA.jar"/>\r
-       <classpathentry kind="lib" path="lib/ant.jar"/>\r
-       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>\r
-       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>\r
-       <classpathentry kind="src" path="src"/>\r
-       <classpathentry kind="src" path="test/src"/>\r
-       <classpathentry exported="true" kind="lib" path="test/lib/powermock-mockito-1.5-full.jar"/>\r
-       <classpathentry exported="true" kind="lib" path="test/lib/mockito-all-1.9.5.jar"/>\r
-       <classpathentry kind="output" path="bin"/>\r
-</classpath>\r
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+       <classpathentry exported="true" kind="lib" path="lib/commons-logging-1.1.1.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/commons-collections-3.2.1.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/commons-pool-1.6.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/commons-lang3-3.1.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/commons-io-2.4.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/freemarker.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/log4j-1.2.17.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/slf4j-api-1.6.4.jar"/>
+       <classpathentry exported="true" kind="lib" path="lib/slf4j-log4j12-1.6.4.jar"/>
+       <classpathentry exported="true" kind="lib" path="test/lib/junit-4.10.jar" sourcepath="test/lib/junit-4.10-src.jar"/>
+       <classpathentry kind="lib" path="test/lib/asm-4.0.jar"/>
+       <classpathentry kind="lib" path="test/lib/asm-tree-4.0.jar"/>
+       <classpathentry exported="true" kind="lib" path="test/lib/javassist-3.16.1-GA.jar"/>
+       <classpathentry kind="lib" path="lib/ant.jar"/>
+       <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
+       <classpathentry kind="con" path="org.eclipse.pde.core.requiredPlugins"/>
+       <classpathentry kind="src" path="src"/>
+       <classpathentry kind="src" path="test/src"/>
+       <classpathentry exported="true" kind="lib" path="test/lib/powermock-mockito-1.5-full.jar"/>
+       <classpathentry exported="true" kind="lib" path="test/lib/mockito-all-1.9.5.jar"/>
+       <classpathentry kind="output" path="bin"/>
+</classpath>
index b40a1bd..cb484bb 100644 (file)
@@ -31,7 +31,7 @@
 -->
 
 <!--
-We use custom log4j appender: org.tizen.common.util.log.TizenLog4Configurator by adding vm argument: -Dlog4j.configuratorClass=org.tizen.common.util.log.TizenLog4Configurator
+We use custom log4j appender: org.tizen.common.util.log.TizenLog4jConfigurator by adding vm argument: -Dlog4j.configuratorClass=org.tizen.common.util.log.TizenLog4jConfigurator
 Above code is initialization code of LogManager, and it executes configurator only if it has log4j configure file in the class path. 
 We need this empty log4j.xml file because configurator is not executed without log4j.xml file.
 -->
index 358a12a..6721fe5 100644 (file)
              id="org.tizen.common.preferences.rds"\r
              name="%RDS.name">\r
        </page>\r
-        <page\r
-              category="org.tizen.common.preferences.tizencommon"\r
-              class="org.tizen.common.util.log.preference.TizenLoggerPreferencePage"\r
-              id="org.tizen.common.preferences.logger"\r
-              name="%preferences.logger.name">\r
-        </page>\r
     </extension>\r
     <extension\r
         point="org.eclipse.ui.startup">\r
index 2ad69fb..c078315 100755 (executable)
@@ -45,6 +45,7 @@ import org.tizen.common.util.DialogUtil;
 import org.tizen.common.util.HostUtil;
 import org.tizen.common.util.OSChecker;
 import org.tizen.common.util.log.Logger;
+import org.tizen.common.util.log.TizenLog4jConfigurator;
 import org.tizen.sdblib.CrashReportService;
 import org.tizen.sdblib.ICrashReportServiceListener;
 import org.tizen.sdblib.SmartDevelopmentBridge;
@@ -79,6 +80,9 @@ public class CommonPlugin extends AbstractUIPlugin {
     @Override
     public void start(BundleContext context) throws Exception {
         super.start( context );
+        
+        getPreferenceStore().addPropertyChangeListener( new TizenLog4jConfigurator() );
+        
         plugin = this;
         initializeExecutor();
 
index ec48dd8..576a112 100644 (file)
@@ -43,6 +43,22 @@ public class Messages {
     public static String RDS_OPTION_SAVE_FAIL;
     public static String RDS_MODE_PREFERENCE;
     
+    public static String LOGGER_GROUP;
+    public static String LABEL_LOG_LOCATION;
+    public static String LABEL_LOG_CP;
+    
+    public static String BUTTON_REPORT;
+    public static String BUTTON_USAGE;
+    public static String BUTTON_PERFORM;
+    
+    public static String DES_OFF;
+    public static String DES_ERROR;
+    public static String DES_WARN;
+    public static String DES_INFO;
+    public static String DES_DEBUG;
+    public static String DES_ALL;
+    
+    
     static {
         // initialize resource bundle
         NLS.initializeMessages( BUNDLE_NAME, Messages.class );
index 8197247..e59d6ea 100644 (file)
@@ -6,4 +6,10 @@ LABEL_UPDATE=Automatically find new updates at start-up and notify me
 PROPERTIES_PAGE_BODY=Expand the tree to edit preferences for a specific feature.
 RDS_NOTE=Currently, this option is not supported for multi-app project.
 RDS_OPTION_SAVE_FAIL=Failed to save options.
-RDS_MODE_PREFERENCE=Enable rapid development mode
\ No newline at end of file
+RDS_MODE_PREFERENCE=Enable rapid development mode
+LOGGER_GROUP=Logger
+LABEL_LOG_LOCATION=&Location
+LABEL_LOG_CP=&Pattern
+BUTTON_REPORT=I want to contribute this information to improve Tizen IDE
+BUTTON_USAGE=Send usage data
+BUTTON_PERFORM=Send performance data
\ No newline at end of file
index 41696eb..4c5b209 100644 (file)
@@ -28,13 +28,27 @@ package org.tizen.common.ui.page.preference;
 import org.eclipse.jface.preference.BooleanFieldEditor;
 import org.eclipse.jface.preference.DirectoryFieldEditor;
 import org.eclipse.jface.preference.FieldEditorPreferencePage;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.swt.SWT;
+import org.eclipse.swt.events.MouseEvent;
+import org.eclipse.swt.events.MouseListener;
+import org.eclipse.swt.events.SelectionEvent;
+import org.eclipse.swt.events.SelectionListener;
 import org.eclipse.swt.layout.GridData;
 import org.eclipse.swt.layout.GridLayout;
+import org.eclipse.swt.widgets.Button;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.swt.widgets.Label;
+import org.eclipse.swt.widgets.Scale;
+import org.eclipse.swt.widgets.Text;
 import org.eclipse.ui.IWorkbench;
 import org.eclipse.ui.IWorkbenchPreferencePage;
 import org.tizen.common.CommonPlugin;
 import org.tizen.common.util.SWTUtil;
+import org.tizen.common.util.StringUtil;
+import org.tizen.common.util.log.FileAppender;
+import org.tizen.common.util.log.Level;
+import org.tizen.common.util.log.LoggerConstants;
 
 public class TizenBasePreferencePage extends FieldEditorPreferencePage implements
         IWorkbenchPreferencePage
@@ -45,9 +59,33 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement
 
     public static final String KEY_SDKLOCATION = "sdkpath"; //$NON-NLS-1$
     public static final String KEY_SDKUPDATE = "sdkupdate"; //$NON-NLS-1$
+    
     public static final String VALUE_SDKLOCATION_DEFAULT = null;;
     public static final boolean VALUE_SDKUPDATE_DEFAULT = false;
+    
+    public static final String OPTION_ID_LEVEL = "org.tizen.common.logger.level";
+    public static final String OPTION_ID_LOCATION = "org.tizen.common.logger.location";
+    public static final String OPTION_ID_CP = "org.tizen.common.logger.cp";
+    public static final String OPTION_ID_REPORT = "org.tizen.common.logger.report";
+    public static final String OPTION_ID_USAGE = "org.tizen.common.logger.usage";
+    public static final String OPTION_ID_PERFORM = "org.tizen.common.logger.perform";
+    
+    private static final String DEFAULT_LOG_LOCATION = "%X{" + LoggerConstants.KEY_WORKSPACE + "}/.metadata/log.%d";
+    
+    private static final int DEFAULT_LEVEL = 1;
+    private static final Level[] LEVELS = {Level.OFF, Level.ERROR, Level.WARNING, Level.INFO, Level.DEBUG, Level.ALL};
+    
+    private Text loggerCP;
+    private Text loggerLocText;
+    private Scale levelScale;
+    private Label levelDesLabel;
+    private Button reportButton;
+    private Button usageButton;
+    private Button performButton;
+    
+    private static final IPreferenceStore prefStore = (CommonPlugin.getDefault() == null) ? null : CommonPlugin.getDefault().getPreferenceStore();
 
+    
     public TizenBasePreferencePage()
     {
         // super(GRID);
@@ -58,9 +96,7 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement
     }
 
     @Override
-    public void init(IWorkbench workbench)
-    {
-        // TODO Auto-generated method stub
+    public void init(IWorkbench workbench) {
     }
 
     @Override
@@ -82,6 +118,7 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement
         SWTUtil.createSpacer(composite, 1);
         createUpdateSettingPreferences(composite);
         SWTUtil.createSpacer(composite, 1);
+        createLoggerPreferences(composite);
     }
 
     private void createPathSettingPreferences(Composite parent)
@@ -103,5 +140,256 @@ public class TizenBasePreferencePage extends FieldEditorPreferencePage implement
                 Messages.LABEL_UPDATE, formatComposite);
         addField(startupCheckEditor);
     }
+    
+
+    private void addLoggerListener() {
+    }
+    
+    private void setLoggerButtonEnablement() {
+        if(prefStore.getBoolean(OPTION_ID_REPORT)) {
+            reportButton.setSelection(true);
+        }
+    }
+
+    private void createLoggerPreferences(Composite parent) {
+        Composite comp = SWTUtil.createGroup(parent, Messages.LOGGER_GROUP, 1);
+        SWTUtil.setGridLayout(comp, 2, false, -1, -1, -1, -1, GridData.FILL_HORIZONTAL);
+        createLoggerLocationButton(comp);
+        createLoggerConversionPatterhn(comp);
+        createLoggerLevelButtons(comp);
+        createLoggerReportButtons(comp);
+        
+        addLoggerListener();
+        setLoggerButtonEnablement();
+    }
+
+    private void createLoggerConversionPatterhn(Composite parent) {
+        Label loggerLocationLabel = new Label(parent, SWT.None);
+        loggerLocationLabel.setText(Messages.LABEL_LOG_CP);
+        
+        loggerCP = new Text(parent, SWT.BORDER);
+        SWTUtil.setGridLayoutData(loggerCP, -1, -1, -1, -1, GridData.FILL_HORIZONTAL);
+        
+        loggerCP.setText(getLogConversionPattern());
+    }
+
+    private void createLoggerReportButtons(Composite parent) {
+        Composite comp = new Composite(parent, SWT.None);
+        SWTUtil.setGridLayout(comp, 2, false, -1, -1, -1, -1, GridData.FILL_HORIZONTAL);
+        SWTUtil.setGridLayoutData(comp, -1, -1, 2, -1, GridData.FILL_HORIZONTAL);
+        
+        reportButton = new Button(comp, SWT.CHECK);
+        SWTUtil.setGridLayoutData(reportButton, -1, -1, 2, -1, GridData.FILL_HORIZONTAL);
+        reportButton.setText(Messages.BUTTON_REPORT);
+        
+        Label emptyLabel = new Label(comp, SWT.None);
+        emptyLabel.setText("   ");
+        
+        usageButton = new Button(comp, SWT.CHECK);
+        SWTUtil.setGridLayoutData(usageButton,  -1, -1, -1, -1, GridData.FILL_HORIZONTAL);
+        usageButton.setText(Messages.BUTTON_USAGE);
+        
+        Label emptyLabel2 = new Label(comp, SWT.None);
+        emptyLabel2.setText("   ");
+        
+        performButton = new Button(comp, SWT.CHECK);
+        SWTUtil.setGridLayoutData(performButton, -1, -1, -1, -1, GridData.FILL_HORIZONTAL);
+        performButton.setText(Messages.BUTTON_PERFORM);
+        
+        if(prefStore.getBoolean(OPTION_ID_REPORT)) {
+            reportButton.setSelection(true);
+            if(prefStore.getBoolean(OPTION_ID_USAGE)) {
+                usageButton.setSelection(true);
+            }
+            if(prefStore.getBoolean(OPTION_ID_PERFORM)) {
+                performButton.setSelection(true);
+            }
+        }
+        
+        checkLoggerButton();
+        
+        reportButton.addSelectionListener(new SelectionListener() {
+            
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                checkLoggerButton();
+            }
+            
+            @Override
+            public void widgetDefaultSelected(SelectionEvent e) {
+            }
+        });
+    }
+    
+    private void checkLoggerButton() {
+        if(!reportButton.getSelection()) {
+            usageButton.setSelection(false);
+            usageButton.setEnabled(false);
+            performButton.setSelection(false);
+            performButton.setEnabled(false);
+        }
+        else {
+            usageButton.setEnabled(true);
+            performButton.setEnabled(true);
+        }
+    }
+
+    private void createLoggerLocationButton(Composite parent) {
+        Label loggerLocationLabel = new Label(parent, SWT.None);
+        loggerLocationLabel.setText(Messages.LABEL_LOG_LOCATION);
+        
+        loggerLocText = new Text(parent, SWT.BORDER);
+        SWTUtil.setGridLayoutData(loggerLocText, -1, -1, -1, -1, GridData.FILL_HORIZONTAL);
+        
+        loggerLocText.setText(getLogLocation());
+    }
+
+    public static String getLogConversionPattern() {
+        
+        String loggerCP = prefStore.getString(OPTION_ID_CP);
+        if(StringUtil.isEmpty(loggerCP)) {
+            loggerCP = LoggerConstants.DEFAULT_CONVERSION_PATTERN;
+        }
+        
+        return loggerCP;
+    }
+    
+    public static String getLogLocation() {
+        
+        String loggerPath = prefStore.getString(OPTION_ID_LOCATION);
+        if(StringUtil.isEmpty(loggerPath)) {
+            loggerPath = DEFAULT_LOG_LOCATION;
+        }
+        
+        return loggerPath;
+    }
+
+    private void createLoggerLevelButtons(Composite parent) {
+        String selectedLevel = prefStore.getString(OPTION_ID_LEVEL);
+        if(StringUtil.isEmpty(selectedLevel)) {
+            selectedLevel = LEVELS[DEFAULT_LEVEL].toString();
+        }
+        
+        levelScale = new Scale(parent, SWT.HORIZONTAL);
+        SWTUtil.setGridLayoutData(levelScale, -1, -1, 2, -1, GridData.FILL_HORIZONTAL);
+        levelScale.setMinimum(0);
+        levelScale.setMaximum(LEVELS.length - 1);
+        levelScale.setIncrement(1);
+        levelScale.setPageIncrement(1);
+//        levelScale.setDragDetect(false);
+        
+        boolean levelDefined = false;
+        for(int i=0; i<LEVELS.length; i++) {
+            Level level = LEVELS[i];
+            
+            if(level.toString().equals(selectedLevel)) {
+                levelDefined = true;
+                levelScale.setSelection(i);
+                break;
+            }
+        }
+        
+        if(!levelDefined) {
+            levelScale.setSelection(DEFAULT_LEVEL);
+        }
+        
+        levelDesLabel = new Label(parent, SWT.None);
+        SWTUtil.setGridLayoutData(levelDesLabel, -1, -1, 2, -1, GridData.FILL_HORIZONTAL);
+        levelDesLabel.setText(LEVELS[levelScale.getSelection()].getDescription());
+        
+        
+        
+        levelScale.addMouseListener(new MouseListener() {
+            
+            @Override
+            public void mouseUp(MouseEvent e) {
+                int selectedLevel = levelScale.getSelection();
+                levelScale.setSelection(selectedLevel);
+            }
+            
+            @Override
+            public void mouseDown(MouseEvent e) {
+            }
+            
+            @Override
+            public void mouseDoubleClick(MouseEvent e) {
+            }
+        });
+        
+        levelScale.addSelectionListener(new SelectionListener() {
+            
+            @Override
+            public void widgetSelected(SelectionEvent e) {
+                levelDesLabel.setText(LEVELS[levelScale.getSelection()].getDescription());
+            }
+            
+            @Override
+            public void widgetDefaultSelected(SelectionEvent e) {
+            }
+        });
+    }
+
+    
+    @Override
+    protected void performDefaults() {
+        
+        levelScale.setSelection(DEFAULT_LEVEL);
+        levelDesLabel.setText(LEVELS[DEFAULT_LEVEL].getDescription());
+        loggerLocText.setText(DEFAULT_LOG_LOCATION);
+        loggerCP.setText(LoggerConstants.DEFAULT_CONVERSION_PATTERN);
+        reportButton.setSelection(false);
+        checkLoggerButton();
+        super.performDefaults();
+    }
+    
+    @Override
+    protected void performApply() {
+        
+        Level loggerLevel = LEVELS[levelScale.getSelection()];
+        prefStore.setValue(OPTION_ID_LOCATION, loggerLocText.getText());
+        prefStore.setValue(OPTION_ID_LEVEL, loggerLevel.toString());
+        prefStore.setValue(OPTION_ID_REPORT, reportButton.getSelection());
+        prefStore.setValue(OPTION_ID_USAGE, usageButton.getSelection());
+        prefStore.setValue(OPTION_ID_PERFORM, performButton.getSelection());
+        prefStore.setValue(OPTION_ID_CP, loggerCP.getText());
+    }
+
+    @Override
+    public boolean performOk() {
+        performApply();
+        return super.performOk();
+    }
+    
+    public static Level getLoggerLevel() {
+        return getLoggerLevel(null);
+    }
+    
+    public static Level getLoggerLevel(String levelString) {
+        
+        if(StringUtil.isEmpty(levelString)) {
+            levelString = prefStore.getString(OPTION_ID_LEVEL);
+        }
+        for(Level level: LEVELS) {
+            if(level.toString().equals(levelString)) {
+                return level;
+            }
+        }
+        return LEVELS[DEFAULT_LEVEL];
+    }
+    
+    public static boolean isReport() {
+        if(prefStore == null) {
+            return false;
+        }
+        return prefStore.getBoolean(OPTION_ID_REPORT);
+    }
+    
+    public static boolean isUsage() {
+        return prefStore.getBoolean(OPTION_ID_USAGE);
+    }
+    
+    public static boolean isPerform() {
+        return prefStore.getBoolean(OPTION_ID_PERFORM);
+    }
 
 }
index 75b12dc..fb12858 100755 (executable)
@@ -642,7 +642,7 @@ public class FileUtil {
      * return appended path with given OS type..
      * @param originalPath original path
      * @param appendPath path which will be appended to original path.
-     * @param iwWindow if you want to get Windows path, true. Else, false.
+     * @param iwWindows if you want to get path of Microsoft Windows, <code>true</code>. Else, <code>false</code>.
      * @return appended path 
      */
     public static String appendPath(String originalPath, String appendPath, boolean isWindows) {
index f8369bf..6b75138 100755 (executable)
@@ -480,6 +480,25 @@ public class SWTUtil {
             }
         } while (!treeStack.isEmpty());
     }
+    
+    /**
+     * set grid layout of the Control
+     * If values of  heightHint, widthHint, horizontalSpan, verticalSpan is -1, this method does not change value of them
+     * 
+     * @param c target control to which grid layout data is set
+     * @param numColumns the number of columns in the grid
+     * @param equalWidth whether or not the columns will have equal width 
+     * @param heightHint height of the control
+     * @param widthHint width of the control
+     * @param horizontalSpan the number of column cells that control will take up
+     * @param verticalSpan the number of row cells that control will take up
+     * @param style style of the control
+     * @author Ho Namkoong {@literal <ho.namkoong@samsung.com>} (S-Core)
+     */
+    public static void setGridLayout(Composite c, int numColumns, boolean equalWidth, int heightHint, int widthHint, int horizontalSpan, int verticalSpan, int style) {
+        c.setLayout(new GridLayout(numColumns, equalWidth));
+        SWTUtil.setGridLayoutData(c, heightHint, widthHint, horizontalSpan, verticalSpan, style);
+    }
 
     /**
      * set grid layout data of Control. 
diff --git a/org.tizen.common/src/org/tizen/common/util/ThreadLocalMap.java b/org.tizen.common/src/org/tizen/common/util/ThreadLocalMap.java
new file mode 100644 (file)
index 0000000..c0b1aae
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * ThreadLocalMap which implements {@link Map}} has one map per one thread
+ * @see ThreadLocal
+ * @see Map
+ * @author ho.namkoong
+ */
+public class ThreadLocalMap<K, V>
+implements Map<K, V> {
+
+    /**
+     * contains one map per one thread
+     */
+    private ThreadLocal<Map<K, V>> threadLocal = new ThreadLocal<Map<K,V>>() {
+        
+        protected Map<K,V> initialValue() {
+            return new HashMap<K, V>();
+        };
+    };
+    
+    @Override
+    public int size() {
+        return threadLocal.get().size();
+    }
+
+    @Override
+    public boolean isEmpty() {
+        return threadLocal.get().isEmpty();
+    }
+
+    @Override
+    public boolean containsKey(Object key) {
+        return threadLocal.get().containsKey(key);
+    }
+
+    @Override
+    public boolean containsValue(Object value) {
+        return threadLocal.get().containsValue(value);
+    }
+
+    @Override
+    public V get(Object key) {
+        return threadLocal.get().get(key);
+    }
+
+    @Override
+    public V put(K key, V value) {
+        return threadLocal.get().put(key, value);
+    }
+
+    @Override
+    public V remove(Object key) {
+        return threadLocal.get().remove(key);
+    }
+
+    @Override
+    public void putAll(Map<? extends K, ? extends V> m) {
+        threadLocal.get().putAll(m);
+    }
+
+    @Override
+    public void clear() {
+        threadLocal.get().clear();
+    }
+
+    @Override
+    public Set<K> keySet() {
+        return threadLocal.get().keySet();
+    }
+
+    @Override
+    public Collection<V> values() {
+        return threadLocal.get().values();
+    }
+
+    @Override
+    public Set<java.util.Map.Entry<K, V>> entrySet() {
+        return threadLocal.get().entrySet();
+    }
+}
 package org.tizen.common.util.log;
 
 import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.EnhancedPatternLayout;
+import org.apache.log4j.Layout;
 import org.apache.log4j.Level;
 import org.apache.log4j.spi.LoggingEvent;
 import org.apache.log4j.spi.ThrowableInformation;
 
-public class TizenLog4jAppender extends AppenderSkeleton{
+public class EclipseAppender extends AppenderSkeleton{
+    
+    public EclipseAppender() {
+        this(new EnhancedPatternLayout(LoggerConstants.DEFAULT_CONVERSION_PATTERN));
+    }
+    
+    public EclipseAppender(Layout layout) {
+        super();
+        setLayout(layout);
+    }
     
     @Override
     public void close() {
@@ -52,8 +63,8 @@ public class TizenLog4jAppender extends AppenderSkeleton{
         if(tI != null) {
             t = tI.getThrowable();
         }
-        Object msg = arg0.getMessage();
-        String message = msg.toString();
+        
+        String message = arg0.getMessage().toString();
         
         switch (level) {
         case Level.ERROR_INT:
diff --git a/org.tizen.common/src/org/tizen/common/util/log/FileAppender.java b/org.tizen.common/src/org/tizen/common/util/log/FileAppender.java
new file mode 100644 (file)
index 0000000..5bcc11a
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Timer;
+import java.util.TimerTask;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.EnhancedPatternLayout;
+import org.apache.log4j.Layout;
+import org.apache.log4j.Logger;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LoggingEvent;
+import org.eclipse.osgi.util.NLS;
+import org.tizen.common.util.IOUtil;
+import org.tizen.common.util.StringUtil;
+
+public class FileAppender extends AppenderSkeleton{
+    
+    private int bufferSize;
+  //This event is dummy for getting formatted workspace path.
+    private static final LoggingEvent dummy = new LoggingEvent( null, Logger.getLogger( "FileAppender"), Level.OFF, StringUtil.EMPTY_STRING, null );
+
+    protected final OutputStream NOOP_OUTPUT_STREAM = new OutputStream() {
+
+        @Override
+        public void write(int b) throws IOException {
+        }
+    };
+    
+    protected final FileAppenderScheduler NOOP_SCHEDULER = new FileAppenderScheduler() {
+        
+        @Override
+        public void run() {}
+        
+        @Override
+        public boolean cancel() {
+            return true;
+        }
+    };
+    
+    private OutputStream  FILE_OUTPUT_STREAM;
+    private FileAppenderScheduler SCHEDULER;
+    private static final Timer TIMER = new Timer("File appender timer", true);
+    protected String logPath;
+
+    public FileAppender(String logPath) {
+        this(logPath, new EnhancedPatternLayout(LoggerConstants.DEFAULT_CONVERSION_PATTERN), LoggerConstants.DEFAULT_BUFFER_SIZE);
+    }
+    
+    public FileAppender(String logPath, Layout layout) {
+        this(logPath, layout, LoggerConstants.DEFAULT_BUFFER_SIZE);
+    }
+    
+    public FileAppender(String logPath, Layout layout, int bufferSize) {
+        super();
+        this.logPath = new EnhancedPatternLayout(logPath).format(dummy);
+        this.bufferSize = bufferSize;
+        setLayout(layout);
+        initializeAppender();
+    }
+
+    @Override
+    public void close() {
+    }
+
+    @Override
+    public boolean requiresLayout() {
+        return false;
+    }
+
+    synchronized public void setFilePath( final String path ) {
+        IOUtil.tryFlush(FILE_OUTPUT_STREAM);
+        IOUtil.tryClose(FILE_OUTPUT_STREAM);
+        EnhancedPatternLayout layout = new EnhancedPatternLayout(path);
+        this.logPath = layout.format(dummy);
+        initializeAppender();
+    }
+    
+    synchronized public void setBufferSize(final int bufferSize) {
+        IOUtil.tryFlush(FILE_OUTPUT_STREAM);
+        IOUtil.tryClose(FILE_OUTPUT_STREAM);
+        this.bufferSize = bufferSize;
+        initializeAppender();
+    }
+
+    @Override
+    synchronized protected void append(LoggingEvent arg0) {
+        
+        try {
+            FILE_OUTPUT_STREAM.write(layout.format(arg0).getBytes());
+            
+            if(getLayout().ignoresThrowable()) {
+                String[] tss = arg0.getThrowableStrRep();
+                if(tss != null) {
+                    for(String ts: tss) {
+                        FILE_OUTPUT_STREAM.write((ts + "\n").getBytes());
+                    }
+                }
+            }
+        } catch (IOException e) {
+            LogLog.error(Messages.FileAppender_EXCEPTION_WRITING_LOG, e); //$NON-NLS-1$
+        }
+
+        SCHEDULER.cancel();
+        SCHEDULER = new FileAppenderScheduler();
+        TIMER.scheduleAtFixedRate(SCHEDULER, LoggerConstants.DEFAULT_TIMER_PERIOD, LoggerConstants.DEFAULT_TIMER_PERIOD);
+    }
+
+    synchronized private void initializeAppender() {
+        
+        File logFile = new File(logPath);
+        
+        if(!logFile.exists()) {
+            logFile.getAbsoluteFile().getParentFile().mkdirs();
+            try {
+                logFile.createNewFile();
+            } catch (IOException e) {
+                FILE_OUTPUT_STREAM = NOOP_OUTPUT_STREAM;
+                SCHEDULER = NOOP_SCHEDULER;
+                LogLog.error(NLS.bind(Messages.FileAppender_EXCEPTION_CREATING_LOGFILE, logPath), e); //$NON-NLS-1$
+                return;
+            }
+        }
+        else if(logFile.isDirectory()) {
+            FILE_OUTPUT_STREAM = NOOP_OUTPUT_STREAM;
+            SCHEDULER = NOOP_SCHEDULER;
+            LogLog.error(NLS.bind(Messages.FileAppender_EXCEPTION_DIRECTORY_EXISTING, logPath));
+            return;
+        }
+
+        IOUtil.tryFlush(FILE_OUTPUT_STREAM);
+        IOUtil.tryClose(FILE_OUTPUT_STREAM);
+        try {
+            FILE_OUTPUT_STREAM = new BufferedOutputStream( new FileOutputStream(logPath, true), this.bufferSize );
+        } catch (IOException e) {
+            FILE_OUTPUT_STREAM = NOOP_OUTPUT_STREAM;
+            SCHEDULER = NOOP_SCHEDULER;
+            LogLog.error(Messages.FileAppender_EXCEPTION_CREATING_BUFFER, e); //$NON-NLS-1$
+            return;
+        }
+        
+        SCHEDULER = new FileAppenderScheduler();
+        TIMER.scheduleAtFixedRate(SCHEDULER, LoggerConstants.DEFAULT_TIMER_PERIOD, LoggerConstants.DEFAULT_TIMER_PERIOD);
+    }
+
+    public class FileAppenderScheduler extends TimerTask {
+        @Override
+        public void run() {
+            synchronized ( FileAppender.this ) {
+                try {
+                    FILE_OUTPUT_STREAM.flush();
+                } catch (IOException e) {
+                    LogLog.error(Messages.FileAppender_EXCEPTION_FLUSHING_BUFFER, e);
+                }
+            }
+        }
+    }
+}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/GoogleAnalyticAppender.java b/org.tizen.common/src/org/tizen/common/util/log/GoogleAnalyticAppender.java
new file mode 100644 (file)
index 0000000..bac9a22
--- /dev/null
@@ -0,0 +1,288 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.net.URLEncoder;
+import java.util.ArrayList;
+
+import org.apache.log4j.AppenderSkeleton;
+import org.apache.log4j.EnhancedPatternLayout;
+import org.apache.log4j.Layout;
+import org.apache.log4j.Level;
+import org.apache.log4j.helpers.LogLog;
+import org.apache.log4j.spi.LoggingEvent;
+import org.tizen.common.util.ObjectUtil;
+import org.tizen.common.util.log.UserLogger.Event;
+import org.tizen.common.util.log.UserLogger.Page;
+import org.tizen.common.util.log.UserLogger.PerformanceInfo;
+
+public
+class
+GoogleAnalyticAppender
+extends AppenderSkeleton
+{
+    private boolean isUsage = false;
+    private boolean isPerform = false;
+    static final String URL_GOOGLE_ANALYTIC = "http://www.google-analytics.com/collect";
+    private static final int MAX_STACK_TRACE = 2;
+    
+    private static final String KEY_ANALYTIC_VER = "v";
+    private static final String KEY_TRACKING_ID = "tid";
+    private static final String KEY_CLIENT_ID = "cid";
+    private static final String KEY_HIT_TYPE = "t";
+    private static final String KEY_APP_NAME = "an";
+    private static final String KEY_APP_VER = "av";
+    private static final String KEY_CONTENT_DES = "cd";
+    private static final String KEY_EVENT_CATEGORY = "ec";
+    private static final String KEY_EVENT_ACTION = "ea";
+    private static final String KEY_PERFORM_CATEGORY = "utc";
+    private static final String KEY_PERFORM_VARIABLE = "utv";
+    private static final String KEY_PERFORM_TIME = "utt";
+    private static final String KEY_EXCEPTION = "exd";
+    private static final String KEY_FATAL = "exf";
+
+    private static final String VALUE_ANALYTIC_VER = "1";
+    private static final String VALUE_TRACKING_ID = "UA-33537119-1";
+    private static final String VALUE_CLIENT_ID = ObjectUtil.generateGUID( GoogleAnalyticAppender.class );
+    private static final String VALUE_APP_NAME = "tizen-ide";
+    private static final String VALUE_APP_VER = "2.1";
+    private static final String VALUE_HIT_TYPE_TIMING = "timing";
+    private static final String VALUE_HIT_TYPE_EVENT = "event";
+//    private static final String VALUE_HIT_TYPE_PAGE = "page";
+//    private static final String VALUE_HIT_TYPE_EXCEPTION = "exception";
+    private static final String VALUE_HIT_TYPE_APP = "appview";
+    int rc;
+    
+    public GoogleAnalyticAppender(boolean isUsage, boolean isPerform) {
+        this(isUsage, isPerform, new EnhancedPatternLayout(LoggerConstants.DEFAULT_CONVERSION_PATTERN));
+    }
+    
+    public GoogleAnalyticAppender(boolean isUsage, boolean isPerform, Layout layout) {
+        super();
+        this.isUsage = isUsage;
+        this.isPerform = isPerform;
+        setLayout(layout);
+    }
+    
+    public void setUsage(boolean isUsage) {
+        this.isUsage = isUsage;
+    }
+    
+    public void setPerform(boolean isPerform) {
+        this.isPerform = isPerform;
+    }
+    
+    @Override
+    public
+    void
+    close()
+    {
+    }
+
+    @Override
+    public boolean requiresLayout()
+    {
+        return false;
+    }
+
+    protected String
+    assembly(
+            final String key,
+            final String value
+            )
+                    throws UnsupportedEncodingException
+                    {
+        return URLEncoder.encode( key, "utf-8" ) + "=" + URLEncoder.encode( value, "utf-8" );
+                    }
+
+    protected
+    String
+    join( String... props )
+    {
+        final StringBuilder buffer = new StringBuilder( 1000 );
+        for ( int i = 0, n = props.length ; i<n ; ++i  )
+        {
+            if ( 0 != i )
+            {
+                buffer.append( "&" );
+            }
+            final String prop = props[i];
+            buffer.append( prop );
+        }
+        return buffer.toString();
+    }
+
+    @Override
+    protected void append(
+            final LoggingEvent event
+            )
+    {
+        rc = 0;
+        ArrayList<String> result = new ArrayList<String>();
+        try {
+            if(!assembleString(result, event)) {
+                return;
+            }
+        } catch (UnsupportedEncodingException e) {
+            LogLog.error("Exception occurred while creating google analytic message", e);
+            return;
+        }
+        
+        final String resultData = join(result.toArray(new String[result.size()]));
+        
+        try
+        {
+            final URL u = new URL( URL_GOOGLE_ANALYTIC );
+            final HttpURLConnection con = (HttpURLConnection) u.openConnection();
+            try
+            {
+                con.setDoOutput( true );
+                final OutputStream out = con.getOutputStream();
+                final OutputStreamWriter writer = new OutputStreamWriter( out );
+                writer.write( resultData );
+                writer.flush();
+
+                rc = con.getResponseCode();
+                if ( 200 <= rc && rc < 300 ) 
+                {
+                    System.out.println("OK");
+                }
+            }
+            finally
+            {
+                con.disconnect();
+            }
+        } catch (MalformedURLException e)
+        {
+            LogLog.debug( String.format("Malformed URL: %s", URL_GOOGLE_ANALYTIC), e );
+        } catch (IOException e)
+        {
+            e.printStackTrace();
+            LogLog.debug( "Exception occurred while transmitting google analytic data.", e );
+        }
+    }
+
+    private boolean assembleString(ArrayList<String> result, LoggingEvent event) throws UnsupportedEncodingException {
+        
+        Level level = event.getLevel();
+        if(level == org.tizen.common.util.log.Level.PERFORM_END) {
+            if(!isPerform) {
+                return false;
+            }
+            PerformanceInfo perform = (PerformanceInfo) event.getMessage();
+            addPerformPreVariables(result, perform);
+            result.add(assembly(KEY_PERFORM_TIME, perform.getPerformanceString()));
+        }
+        else if(level == org.tizen.common.util.log.Level.PERFORM_START) {
+            if(!isPerform) {
+                return false;
+            }
+            PerformanceInfo perform = (PerformanceInfo) event.getMessage();
+            addPerformPreVariables(result, perform);
+        }
+        else if(level == org.tizen.common.util.log.Level.PAGE) {
+            if(!isUsage) {
+                return false;
+            }
+            addPageVariable(result, (Page)event.getMessage());
+        }
+        else if(level == org.tizen.common.util.log.Level.EVENT) {
+            if(!isUsage) {
+                return false;
+            }
+            addEventVariable(result, (Event)event.getMessage());
+        }
+        else {
+            result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_APP));
+        }
+        
+        addBasicInfo(result, event);
+        return true;
+    }
+
+    private void addPageVariable(ArrayList<String> result, Page page) throws UnsupportedEncodingException {
+        result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_EVENT));
+        result.add(assembly(KEY_EVENT_CATEGORY, page.getCategory()));
+    }
+
+    private void addEventVariable(ArrayList<String> result, Event event) throws UnsupportedEncodingException {
+        result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_EVENT));
+        result.add(assembly(KEY_EVENT_CATEGORY, event.getCategory()));
+        result.add(assembly(KEY_EVENT_ACTION, event.getAction()));
+    }
+
+    private void addPerformPreVariables(ArrayList<String> result, PerformanceInfo performanceInfo) throws UnsupportedEncodingException {
+        result.add(assembly(KEY_HIT_TYPE, VALUE_HIT_TYPE_TIMING));
+        result.add(assembly(KEY_PERFORM_CATEGORY, performanceInfo.getCategory()));
+        result.add(assembly(KEY_PERFORM_VARIABLE, performanceInfo.getVariableName()));
+    }
+
+    private void addBasicInfo(ArrayList<String> result, LoggingEvent event) throws UnsupportedEncodingException {
+        
+        //HTTP error 413 occurred if request entity is too large. Just getting the first tss.
+        String[] tss = event.getThrowableStrRep();
+        Level level = event.getLevel();
+        StringBuffer msg = new StringBuffer();
+        msg.append(getLayout().format(event));
+        if(tss != null) {
+            
+            if(level == org.tizen.common.util.log.Level.FATAL) {
+                result.add(assembly(KEY_FATAL, "FATAL"));
+            }
+            StringBuffer tBuffer = new StringBuffer();
+            
+            int i=0;
+            for(String ts: tss) {
+                if(MAX_STACK_TRACE > i + 1) {
+                    tBuffer.append(ts + "\n");
+                    i++;
+                }
+                else {
+                    break;
+                }
+            }
+            result.add(assembly(KEY_EXCEPTION, tBuffer.toString()));
+            
+            if(getLayout().ignoresThrowable()) {
+                msg.append(tBuffer);
+            }
+        }
+        result.add(assembly(KEY_ANALYTIC_VER, VALUE_ANALYTIC_VER));
+        result.add(assembly(KEY_TRACKING_ID, VALUE_TRACKING_ID));
+        result.add(assembly(KEY_CLIENT_ID, VALUE_CLIENT_ID));
+        result.add(assembly(KEY_APP_NAME, VALUE_APP_NAME));
+        result.add(assembly(KEY_APP_VER, VALUE_APP_VER));
+        result.add(assembly(KEY_CONTENT_DES, msg.toString()));
+    }
+}
\ No newline at end of file
diff --git a/org.tizen.common/src/org/tizen/common/util/log/Level.java b/org.tizen.common/src/org/tizen/common/util/log/Level.java
new file mode 100644 (file)
index 0000000..c84597d
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+package org.tizen.common.util.log;
+
+public class Level extends org.apache.log4j.Level{
+    
+    private static final long serialVersionUID = 5540784843364335844L;
+    
+    /**
+     * Logging level page
+     */
+    public static final Level PAGE = new Level(25000, "PAGE", 5);
+    
+    /**
+     * Logging level event
+     */
+    public static final Level EVENT = new Level(23000, "EVENT", 5);
+    
+    /**
+     * Logging level performance start
+     */
+    public static final Level PERFORM_START = new Level(27000, "PERFORM_START", 5);
+    
+    /**
+     * Logging level performance end
+     */
+    public static final Level PERFORM_END = new Level(27000, "PERFFORM_END", 5);
+    
+    /**
+     * Logging level off
+     */
+    public static final Level OFF = new Level(org.apache.log4j.Level.OFF, Messages.LOGGER_OFF_DES);
+    
+    /**
+     * Logging level error
+     */
+    public static final Level ERROR = new Level(org.apache.log4j.Level.ERROR, Messages.LOGGER_ERROR_DES);
+    
+    /**
+     * Logging level warning
+     */
+    public static final Level WARNING = new Level(org.apache.log4j.Level.WARN, Messages.LOGGER_WARNING_DES);
+    
+    /**
+     * Logging level info
+     */
+    public static final Level INFO = new Level(org.apache.log4j.Level.INFO, Messages.LOGGER_INFO_DES);
+    
+    /**
+     * Logging level debug
+     */
+    public static final Level DEBUG = new Level(org.apache.log4j.Level.DEBUG, Messages.LOGGER_DEBUG_DES);
+    
+    /**
+     * Logging level all
+     */
+    public static final Level ALL = new Level(org.apache.log4j.Level.ALL, Messages.LOGGER_ALL_DES);
+    
+    private String description;
+    
+    protected Level(int level, String levelStr, int syslogEquivalent) {
+        super(level, levelStr, syslogEquivalent);
+        this.description = "";
+    }
+    
+    protected Level(org.apache.log4j.Level level, String desc) {
+        this(level.toInt(), level.toString(), level.getSyslogEquivalent());
+        this.description = desc;
+    }
+    
+    public String getDescription() {
+        return description;
+    }
+    
+    
+    @Override
+    public int hashCode() {
+        // TODO Auto-generated method stub
+        return toString().hashCode();
+    }
+}
index 59d1721..050b7e3 100644 (file)
@@ -37,10 +37,17 @@ import org.tizen.common.ui.view.console.ConsoleManager;
 /**
  * Logger.
  * @author Changhyun Lee {@literal <changhyun1.lee@samsung.com>} (S-Core)
+ * @deprecated Use {@link org.slf4j.Logger}} instead.
  */
 public class Logger {
     private static String loggerName = Logger.class.getName();
 
+    
+    /**
+     * 
+     * @param status
+     * @deprecated Use {@link org.apache.log4j.Logger#log(org.apache.log4j.Priority, Object)} instead
+     */
     public static void log(IStatus status) {
         CommonPlugin plugin = CommonPlugin.getDefault();
         if (plugin != null) {
@@ -67,6 +74,11 @@ public class Logger {
         return "noname";
     }
 
+    /**
+     * 
+     * @param e
+     * @deprecated Use {@link org.apache.log4j.Logger#log(org.apache.log4j.Priority, Object, Throwable)} instead
+     */
     public static void log(Throwable e) {
         if (e instanceof CoreException) {
             log(new Status(IStatus.ERROR, getCallerName(), ((CoreException) e).getStatus().getSeverity(), e.getMessage(), e.getCause()));
@@ -74,24 +86,43 @@ public class Logger {
             log(new Status(IStatus.ERROR, getCallerName(), e.toString(), e));
         }
     }
-    
-    public static void debug( String message, Object... arguments )
-    {
-       
-    }
 
+    /**
+     * 
+     * @param message
+     * @param arguments
+     * @deprecated Use {@link org.slf4j.Logger#info(String, Object[])} instead
+     */
     public static void info(String message, Object... arguments) {
         log(new Status(Status.INFO, getCallerName(), getPossiblyFormattedString(message, arguments)));
     }
 
+    /**
+     * 
+     * @param message
+     * @param t
+     * @deprecated Use {@link org.slf4j.Logger#error(String, Throwable)} instead
+     */
     public static void error(Object message, Throwable t) {
         log(new Status(Status.ERROR, getCallerName(), message.toString(), t));
     }
 
+    /**
+     * 
+     * @param message
+     * @param arguments
+     * @deprecated Use {@link org.slf4j.Logger#error(String, Object[])} instead
+     */
     public static void error(String message, Object... arguments) {
         log(new Status(Status.ERROR, getCallerName(), getPossiblyFormattedString(message, arguments)));
     }
 
+    /**
+     * 
+     * @param message
+     * @param arguments
+     * @deprecated Use {@link org.slf4j.Logger#warn(String, Object[])} instead
+     */
     public static void warning(String message, Object... arguments) {
         log(new Status(Status.WARNING, getCallerName(), getPossiblyFormattedString(message, arguments)));
     }
diff --git a/org.tizen.common/src/org/tizen/common/util/log/LoggerConstants.java b/org.tizen.common/src/org/tizen/common/util/log/LoggerConstants.java
new file mode 100644 (file)
index 0000000..a56c862
--- /dev/null
@@ -0,0 +1,38 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+package org.tizen.common.util.log;
+
+public class LoggerConstants {
+    
+    public static final String DEFAULT_CONVERSION_PATTERN = "[%p] %F(%L) - %m%n";
+    public static final int DEFAULT_BUFFER_SIZE = 5000;
+    public static final long DEFAULT_TIMER_PERIOD = 3000;
+    public static final String KEY_WORKSPACE = "workspace";
+    public static final String KEY_SDK_HOME = "tizensdk";
+
+}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/Messages.java b/org.tizen.common/src/org/tizen/common/util/log/Messages.java
new file mode 100644 (file)
index 0000000..30bd24b
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import org.eclipse.osgi.util.NLS;
+import org.tizen.common.CommonPlugin;
+
+public class Messages {
+    
+    private static final String BUNDLE_NAME = CommonPlugin.PLUGIN_ID + ".util.log.messages";//$NON-NLS-1$
+
+    private Messages() {
+        // Do not instantiate
+    }
+    
+    public static String UserLogger_EVENT_STRING;
+    public static String FileAppender_EXCEPTION_FLUSHING_BUFFER;
+    public static String FileAppender_EXCEPTION_CREATING_BUFFER;
+    public static String FileAppender_EXCEPTION_CREATING_LOGFILE;
+    public static String FileAppender_EXCEPTION_WRITING_LOG;
+    public static String FileAppender_EXCEPTION_DIRECTORY_EXISTING;
+    public static String LOGGER_OFF_DES;
+    public static String LOGGER_ERROR_DES;
+    public static String LOGGER_WARNING_DES;
+    public static String LOGGER_INFO_DES;
+    public static String LOGGER_DEBUG_DES;
+    public static String LOGGER_ALL_DES;
+    
+    static {
+        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
+    }
+}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4Configurator.java b/org.tizen.common/src/org/tizen/common/util/log/TizenLog4Configurator.java
deleted file mode 100644 (file)
index 3ddac07..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- *  Common
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
- *
- * Contact: 
- * Ho Namkoong <ho.namkoong@samsung.com>
- * 
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- * Contributors:
- * - S-Core Co., Ltd
- *
- */
-
-package org.tizen.common.util.log;
-
-import java.io.InputStream;
-import java.net.URL;
-
-import org.apache.log4j.Appender;
-import org.apache.log4j.Level;
-import org.apache.log4j.Logger;
-import org.apache.log4j.spi.Configurator;
-import org.apache.log4j.spi.LoggerRepository;
-import org.tizen.common.util.log.preference.TizenLoggerPreferencePage;
-
-public class TizenLog4Configurator implements Configurator  {
-
-    private static Logger ROOT_LOGGER;
-    
-    @Override
-    public void doConfigure(InputStream arg0, LoggerRepository arg1) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    public void doConfigure(URL arg0, LoggerRepository arg1) {
-        arg1.resetConfiguration();
-        Logger rootLogger = arg1.getRootLogger();
-        
-        rootLogger.removeAllAppenders();
-        Appender tizenAppender = new TizenLog4jAppender();
-        rootLogger.addAppender(tizenAppender);
-        ROOT_LOGGER = rootLogger;
-        
-        setLoggerLevel(TizenLoggerPreferencePage.getLoggerLevel());
-    }
-    
-    public static void setLoggerLevel(String level) {
-        if(ROOT_LOGGER != null) {
-            if(TizenLoggerPreferencePage.LEVEL_ERROR.equals(level)) {
-                ROOT_LOGGER.setLevel(Level.ERROR);
-            }
-            else if(TizenLoggerPreferencePage.LEVEL_WARN.equals(level)) {
-                ROOT_LOGGER.setLevel(Level.WARN);
-            }
-            else if(TizenLoggerPreferencePage.LEVEL_INFO.equals(level)) {
-                ROOT_LOGGER.setLevel(Level.INFO);
-            }
-            else if(TizenLoggerPreferencePage.LEVEL_DEBUG.equals(level)) {
-                ROOT_LOGGER.setLevel(Level.DEBUG);
-            }
-        }
-    }
-
-}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jConfigurator.java b/org.tizen.common/src/org/tizen/common/util/log/TizenLog4jConfigurator.java
new file mode 100644 (file)
index 0000000..deeaa56
--- /dev/null
@@ -0,0 +1,138 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.log4j.AsyncAppender;
+import org.apache.log4j.EnhancedPatternLayout;
+import org.apache.log4j.Logger;
+import org.apache.log4j.MDC;
+import org.apache.log4j.spi.LoggerRepository;
+import org.apache.log4j.xml.DOMConfigurator;
+import org.eclipse.core.resources.ResourcesPlugin;
+import org.eclipse.jface.util.IPropertyChangeListener;
+import org.eclipse.jface.util.PropertyChangeEvent;
+import org.tizen.common.core.application.InstallPathConfig;
+import org.tizen.common.ui.page.preference.TizenBasePreferencePage;
+
+public class TizenLog4jConfigurator extends DOMConfigurator implements IPropertyChangeListener  {
+    
+    private static Logger rootLogger;
+    private static Logger userLogger;
+    private static FileAppender fileAppender;
+    private static AsyncAppender asyncAppender;
+    private static GoogleAnalyticAppender googleAppender;
+    private static EclipseAppender eclipseAppender;
+    
+    private static final EnhancedPatternLayout layout = new EnhancedPatternLayout();
+    
+    @Override
+    public void doConfigure(InputStream arg0, LoggerRepository arg1) {
+        // TODO Auto-generated method stub
+    }
+
+    @Override
+    public void doConfigure(URL arg0, LoggerRepository arg1) {
+        arg1.resetConfiguration();
+        layout.setConversionPattern(TizenBasePreferencePage.getLogConversionPattern());
+        configRootLogger(arg1);
+        configUserLogger();
+    }
+    
+    private void configUserLogger() {
+        userLogger = Logger.getLogger(UserLogger.NAME_USER_LOGGER);
+        asyncAppender = new AsyncAppender();
+        googleAppender =  new GoogleAnalyticAppender(TizenBasePreferencePage.isUsage(), TizenBasePreferencePage.isPerform(), layout);
+        asyncAppender.addAppender(googleAppender);
+        userLogger.addAppender(asyncAppender);
+    }
+
+    private void configRootLogger(LoggerRepository arg1) {
+        Logger _rootLogger = arg1.getRootLogger();
+        rootLogger = _rootLogger;
+        rootLogger.removeAllAppenders();
+        rootLogger.setLevel(TizenBasePreferencePage.getLoggerLevel());
+        
+        MDC.put(LoggerConstants.KEY_WORKSPACE, ResourcesPlugin.getWorkspace().getRoot().getLocation().toString());
+        MDC.put(LoggerConstants.KEY_SDK_HOME, InstallPathConfig.getSDKPath());
+        fileAppender = new FileAppender(TizenBasePreferencePage.getLogLocation(), layout);
+        rootLogger.addAppender(fileAppender);
+        MDC.remove(LoggerConstants.KEY_WORKSPACE);
+        MDC.remove(LoggerConstants.KEY_SDK_HOME);
+        
+        eclipseAppender = new EclipseAppender(layout);
+        rootLogger.addAppender(eclipseAppender);
+    }
+
+    private void setLogFilePath(String name) {
+        MDC.put(LoggerConstants.KEY_WORKSPACE, ResourcesPlugin.getWorkspace().getRoot().getLocation().toString());
+        MDC.put(LoggerConstants.KEY_SDK_HOME, InstallPathConfig.getSDKPath());
+        fileAppender.setFilePath(name);
+        MDC.remove(LoggerConstants.KEY_WORKSPACE);
+        MDC.remove(LoggerConstants.KEY_SDK_HOME);
+    }
+
+    @Override
+    public void propertyChange(PropertyChangeEvent event) {
+        String property = event.getProperty();
+        
+        if(property.equals(TizenBasePreferencePage.OPTION_ID_LOCATION)) {
+            String newPath = (String) event.getNewValue();
+            
+            setLogFilePath(newPath);
+        }
+        else if(property.equals(TizenBasePreferencePage.OPTION_ID_LEVEL)) {
+            String loggerLevel = (String) event.getNewValue();
+            Level level = TizenBasePreferencePage.getLoggerLevel(loggerLevel);
+            rootLogger.setLevel(level);
+            userLogger.setLevel(level);
+        }
+        else if(property.equals(TizenBasePreferencePage.OPTION_ID_REPORT)) {
+            boolean isReport = (Boolean) event.getNewValue();
+            if(isReport) {
+                asyncAppender.addAppender(googleAppender);
+            }
+            else {
+                asyncAppender.removeAppender(googleAppender);
+            }
+        }
+        else if(property.equals(TizenBasePreferencePage.OPTION_ID_USAGE)) {
+            boolean isUsage = (Boolean) event.getNewValue();
+            googleAppender.setUsage(isUsage);
+        }
+        else if(property.equals(TizenBasePreferencePage.OPTION_ID_PERFORM)) {
+            boolean isPerform = (Boolean) event.getNewValue();
+            googleAppender.setUsage(isPerform);
+        }
+        else if(property.equals(TizenBasePreferencePage.OPTION_ID_CP)) {
+            String cp = (String) event.getNewValue();
+            layout.setConversionPattern(cp);
+        }
+    }
+
+}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/UserLogger.java b/org.tizen.common/src/org/tizen/common/util/log/UserLogger.java
new file mode 100644 (file)
index 0000000..b594503
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact: 
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.apache.log4j.Logger;
+import org.tizen.common.util.StringUtil;
+import org.tizen.common.util.ThreadLocalMap;
+
+public class UserLogger {
+
+    protected static ThreadLocalMap<String, Long> id2perform = new ThreadLocalMap<String, Long>();
+
+    private static final String FQCN = UserLogger.class.getName();
+    public static final String NAME_USER_LOGGER = "UserLogger";
+    private static final SimpleDateFormat logDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
+
+    private static Logger logger = Logger.getLogger(NAME_USER_LOGGER);
+
+    public static void page(String category) {
+        page(category, null);
+    }
+
+    public static void page(String category, Throwable t) {
+        if (Level.PAGE.isGreaterOrEqual(logger.getEffectiveLevel())) {
+            Page message = new Page(category);
+            System.out.println("LOGGING IN");
+            logger.log(FQCN, Level.PAGE, message, t);
+        }
+    }
+    
+    public static void event(String category) {
+        event(category, StringUtil.EMPTY_STRING, null);
+    }
+
+    public static void event(String category, String action) {
+        event(category, action, null);
+    }
+    
+    public static void event(String category, String action, Throwable t) {
+        if (Level.EVENT.isGreaterOrEqual(logger.getEffectiveLevel())) {
+            Event message = new Event(category, action);
+            logger.log(FQCN, Level.EVENT, message, t);
+        }
+    }
+
+    public static void start(String category) {
+        start(category, StringUtil.EMPTY_STRING);
+    }
+
+    public static void start(String category, String variableName) {
+        if(Level.PERFORM_START.isGreaterOrEqual(logger.getEffectiveLevel())) {
+            
+            long start = System.currentTimeMillis();
+            id2perform.put( category + variableName, start );
+            PerformanceInfo message = new PerformanceInfo(category, start, 0, variableName);
+            logger.log(FQCN, Level.PERFORM_START, message, null);
+        }
+    }
+
+    public static void end(String category) {
+        end(category, StringUtil.EMPTY_STRING);
+    }
+
+    public static void end(String category, String variableName) {
+        if (Level.PERFORM_END.isGreaterOrEqual(logger.getEffectiveLevel())) {
+            long end = System.currentTimeMillis();
+            Long start = id2perform.remove(category + variableName);
+            if (null == start) {
+                return;
+            }
+            
+            PerformanceInfo message = new PerformanceInfo(category, start, end, variableName);
+            logger.log(FQCN, Level.PERFORM_END, message, null);
+        }
+    }
+    
+    public static class PerformanceInfo {
+        
+        final private String category;
+        final private long start;
+        final private long end;
+        final private String variableName;
+        final private String message;
+        
+        public PerformanceInfo(String category, long start, long end) {
+            this(category, start, end, null);
+        }
+        
+        public PerformanceInfo(String category, long start, long end, String variableName) {
+            this.category = category;
+            this.start = start;
+            this.end = end;
+            this.variableName = variableName;
+            if(end == 0) {
+                if(StringUtil.isEmpty(variableName)) {
+                    this.message = String.format("[Category: %s] at %s", category, logDateFormat.format(new Date(start)));
+                }
+                else {
+                    this.message = String.format("[Category: %s\tVariable: %s] at %s", category, variableName, logDateFormat.format(new Date(start)));
+                }
+            }
+            else {
+                if(StringUtil.isEmpty(variableName)) {
+                    this.message = String.format("[Category: %s] at %s \t [%s(ms)]", category, logDateFormat.format(new Date(end)), getPerformanceString());
+                }
+                else{
+                    this.message = String.format("[Category: %s\tVariable: %s] at %s \t [%s(ms)]", category, variableName, logDateFormat.format(new Date(end)), getPerformanceString());
+                }
+            }
+        }
+
+        @Override
+        public String toString() {
+            return this.message;
+        }
+        
+        public String getCategory() {
+            return category;
+        }
+        
+        public String getVariableName() {
+            return variableName;
+        }
+        
+        public String getPerformanceString() {
+            return String.format("%d", (this.end - this.start));
+        }
+    }
+      
+      public static class Event {
+          
+          final private String category;
+          final private String action;
+          final private String message;
+          
+          public Event(String category) {
+              this(category, null);
+          }
+          
+          public Event(String category, String action) {
+              this.category = category;
+              this.action = action;
+              
+              if(StringUtil.isEmpty(action)) {
+                  this.message = String.format(
+                          "[Category: %s]", category
+                          );
+              }
+              else {
+                  this.message = String.format(
+                          "[Category: %s\tAction: %s]", category,
+                          action);
+              }
+
+          }
+          
+          public String getCategory() {
+              return category;
+          }
+          
+          public String getAction() {
+              return action;
+          }
+          
+          @Override
+          public String toString() {
+              return message;
+          }
+      }
+      
+      public static class Page {
+          
+          final private String category;
+          final private String message;
+          
+          public Page(String category) {
+              this.category = category;
+              this.message = String.format("[Category: %s]",
+                      this.category);
+          }
+          
+          public String getCategory() {
+              return category;
+          }
+          
+          @Override
+          public String toString() {
+              return this.message;
+          }
+          
+          
+      }
+}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/messages.properties b/org.tizen.common/src/org/tizen/common/util/log/messages.properties
new file mode 100644 (file)
index 0000000..68d6113
--- /dev/null
@@ -0,0 +1,12 @@
+FileAppender_EXCEPTION_CREATING_BUFFER=Exception occurred while creating buffered writer.
+FileAppender_EXCEPTION_CREATING_LOGFILE=Exception occurred while creating log file: {0}.
+FileAppender_EXCEPTION_FLUSHING_BUFFER=Exception occurred while flushing buffer.
+FileAppender_EXCEPTION_WRITING_LOG=Exception occurred while writing log message.
+FileAppender_EXCEPTION_DIRECTORY_EXISTING=Log File {0} already exists as a directory.
+LOGGER_OFF_DES=off
+LOGGER_ERROR_DES=error
+LOGGER_WARNING_DES=warning
+LOGGER_INFO_DES=info
+LOGGER_DEBUG_DES=debug
+LOGGER_ALL_DES=all
+UserLogger_EVENT_STRING=Category: {0}\tAction: {1}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/preference/Messages.java b/org.tizen.common/src/org/tizen/common/util/log/preference/Messages.java
deleted file mode 100644 (file)
index 194a778..0000000
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
-* Common
-*
-* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
-*
-* Contact:
-* Kangho Kim <kh5325.kim@samsung.com>
-* NamKoong Ho <ho.namkoong@samsung.com>
-*  
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*
-* Contributors:
-* - S-Core Co., Ltd
-*
-*/
-
-package org.tizen.common.util.log.preference;
-
-import org.eclipse.osgi.util.NLS;
-import org.tizen.common.CommonPlugin;
-
-public class Messages extends NLS {
-
-    private static final String BUNDLE_NAME = CommonPlugin.PLUGIN_ID + ".util.log.preference.messages";//$NON-NLS-1$
-
-    private Messages() {
-        // Do not instantiate
-    }
-    
-    public static String TizenLoggerPreferencePage_Description;
-    public static String TizenLoggerPreferencePage_LevelGroupTitle;
-    
-    static {
-        NLS.initializeMessages(BUNDLE_NAME, Messages.class);
-    }
-}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/preference/TizenLoggerPreferencePage.java b/org.tizen.common/src/org/tizen/common/util/log/preference/TizenLoggerPreferencePage.java
deleted file mode 100644 (file)
index 424afda..0000000
+++ /dev/null
@@ -1,140 +0,0 @@
-/*
-* Common
-*
-* Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
-*
-* Contact:
-* Kangho Kim <kh5325.kim@samsung.com>
-* NamKoong Ho <ho.namkoong@samsung.com>
-*  
-* Licensed under the Apache License, Version 2.0 (the "License");
-* you may not use this file except in compliance with the License.
-* You may obtain a copy of the License at
-*
-* http://www.apache.org/licenses/LICENSE-2.0
-*
-* Unless required by applicable law or agreed to in writing, software
-* distributed under the License is distributed on an "AS IS" BASIS,
-* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-* See the License for the specific language governing permissions and
-* limitations under the License.
-*
-* Contributors:
-* - S-Core Co., Ltd
-*
-*/
-
-package org.tizen.common.util.log.preference;
-
-import java.util.HashMap;
-import org.eclipse.jface.preference.IPreferenceStore;
-import org.eclipse.jface.preference.PreferencePage;
-import org.eclipse.swt.SWT;
-import org.eclipse.swt.events.SelectionEvent;
-import org.eclipse.swt.events.SelectionListener;
-import org.eclipse.swt.layout.GridData;
-import org.eclipse.swt.layout.GridLayout;
-import org.eclipse.swt.widgets.Button;
-import org.eclipse.swt.widgets.Composite;
-import org.eclipse.swt.widgets.Control;
-import org.eclipse.swt.widgets.Group;
-import org.eclipse.ui.IWorkbench;
-import org.eclipse.ui.IWorkbenchPreferencePage;
-import org.tizen.common.CommonPlugin;
-import org.tizen.common.util.log.TizenLog4Configurator;
-
-public class TizenLoggerPreferencePage extends PreferencePage implements IWorkbenchPreferencePage {
-    
-    private static final IPreferenceStore prefStore = CommonPlugin.getDefault().getPreferenceStore();
-    private Button selectedButton;
-    public static final String OPTION_ID_LEVEL = "org.tizen.common.logger.level";
-    
-    public static final String LEVEL_ERROR = "&Error";
-    public static final String LEVEL_WARN = "&Warning";
-    public static final String LEVEL_INFO = "&Info";
-    public static final String LEVEL_DEBUG = "&Debug";
-    
-    private HashMap<String, Button> buttonMap = new HashMap<String, Button>();
-    private final String[] levels = {LEVEL_ERROR, LEVEL_WARN, LEVEL_INFO, LEVEL_DEBUG};
-    
-    public TizenLoggerPreferencePage() {
-        setDescription(Messages.TizenLoggerPreferencePage_Description);
-    }
-
-    @Override
-    public void init(IWorkbench workbench) {
-        // TODO Auto-generated method stub
-    }
-
-    @Override
-    protected Control createContents(Composite parent) {
-        Composite composite = new Composite(parent, SWT.None);
-        composite.setLayout(new GridLayout(1, false));
-        
-        Group levelGroup = new Group(composite, SWT.None);
-        levelGroup.setLayout(new GridLayout(levels.length, false));
-        levelGroup.setLayoutData(new GridData(GridData.FILL_HORIZONTAL));
-        levelGroup.setText(Messages.TizenLoggerPreferencePage_LevelGroupTitle);
-        
-        for(String level: levels) {
-            final Button radioButton = new Button(levelGroup, SWT.RADIO);
-            radioButton.setText(level);
-            buttonMap.put(level, radioButton);
-            radioButton.addSelectionListener(new SelectionListener() {
-                
-                @Override
-                public void widgetSelected(SelectionEvent e) {
-                    selectedButton = radioButton;
-                }
-                
-                @Override
-                public void widgetDefaultSelected(SelectionEvent e) {
-                }
-            });
-        }
-        
-        String selection = prefStore.getString(OPTION_ID_LEVEL);
-        Button selected = buttonMap.get(selection);
-        
-        selectedButton = (selected != null) ? selected : buttonMap.get(LEVEL_ERROR);
-        selectedButton.setSelection(true);
-        
-        return composite;
-    }
-    
-    public static String getLoggerLevel() {
-        String level = prefStore.getString(OPTION_ID_LEVEL);
-        
-        if(level != null) {
-            return level;
-        }
-        
-        return LEVEL_ERROR;
-    }
-    
-    @Override
-    protected void performDefaults() {
-        selectedButton.setSelection(false);
-        Button defaultButton = buttonMap.get(LEVEL_ERROR);
-        defaultButton.setSelection(true);
-        selectedButton = defaultButton;
-        TizenLog4Configurator.setLoggerLevel(LEVEL_ERROR);
-        super.performDefaults();
-    }
-    
-    @Override
-    protected void performApply() {
-        if(selectedButton != null) {
-            String selection = selectedButton.getText();
-            prefStore.putValue(OPTION_ID_LEVEL, selection);
-            TizenLog4Configurator.setLoggerLevel(selection);
-        }
-    }
-
-    @Override
-    public boolean performOk() {
-        performApply();
-        return super.performOk();
-    }
-    
-}
diff --git a/org.tizen.common/src/org/tizen/common/util/log/preference/messages.properties b/org.tizen.common/src/org/tizen/common/util/log/preference/messages.properties
deleted file mode 100644 (file)
index 79ab7a8..0000000
+++ /dev/null
@@ -1,2 +0,0 @@
-TizenLoggerPreferencePage_Description=Set the preferences about the logger
-TizenLoggerPreferencePage_LevelGroupTitle=Logger Level
diff --git a/org.tizen.common/test/src/org/tizen/common/util/log/FileAppenderTest.java b/org.tizen.common/test/src/org/tizen/common/util/log/FileAppenderTest.java
new file mode 100644 (file)
index 0000000..d5e09a6
--- /dev/null
@@ -0,0 +1,224 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import java.io.File;
+import java.io.IOException;
+import static junit.framework.Assert.*;
+
+import org.apache.log4j.EnhancedPatternLayout;
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import static org.powermock.api.mockito.PowerMockito.*;
+import org.tizen.common.util.FileUtil;
+import org.tizen.common.util.StringUtil;
+
+public class FileAppenderTest {
+
+    private static final String TEST_LOG_FILE_FIRST = "test1.txt";
+    private static final String TEST_LOG_FILE_SECOND = "test2.txt";
+    private static final String TEST_LOG_FILE_NOOP = "noop.txt";
+    private static final String RESULT = "A";
+    private static final String BUFFER_RESULT_FIRST = "AAAAA";
+    private static final String BUFFER_RESULT_SECOND = "BBBBB";
+    
+    private FileAppender appender;
+    private EnhancedPatternLayout TEST_LAYOUT = new EnhancedPatternLayout("%m");
+    private LoggingEvent event;
+    
+    /**
+     * Sets up the test
+     * 
+     * @throws Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+        File testFile = new File(TEST_LOG_FILE_FIRST);
+        if(testFile.exists()) {
+            testFile.delete();
+        }
+        
+        File testFile2 = new File(TEST_LOG_FILE_SECOND);
+        if(testFile2.exists()) {
+            testFile2.delete();
+        }
+        
+        appender = new FileAppender(TEST_LOG_FILE_FIRST, TEST_LAYOUT, 5);
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, RESULT, null );
+    }
+
+    /**
+     * 
+     * TestCase for {@link FileAppender#append(LoggingEvent)}
+     * It tests timeout
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void test_append_timeout() throws Exception {
+        appender.append(event);
+        String emptyResult = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(StringUtil.EMPTY_STRING, emptyResult);
+        
+        Thread.sleep(4000);
+        
+        String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(RESULT, result);
+    }
+    
+    /**
+     * 
+     * TestCase for {@link FileAppender#append(LoggingEvent)}
+     * It tests buffer overflow
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void test_appender_bufferover() throws Exception {
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null );
+        appender.append(event);
+        String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST, result);
+        
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_SECOND, null );
+        appender.append(event);
+        result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST +  BUFFER_RESULT_SECOND, result);
+    }
+    
+    /**
+     * 
+     * TestCase for {@link FileAppender#setFilePath(String)}
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void test_setFilePath() throws Exception {
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null );
+        appender.append(event);
+        String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST, result);
+        
+        appender.setFilePath(TEST_LOG_FILE_SECOND);
+        
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_SECOND, null );
+        appender.append(event);
+        result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST, result);
+        result = FileUtil.readTextFile(new File(TEST_LOG_FILE_SECOND), null);
+        assertEquals(BUFFER_RESULT_SECOND, result);
+    }
+    
+    /**
+     * 
+     * TestCase for {@link FileAppender#setBufferSize(int)}
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void test_setBufferSize() throws Exception {
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null );
+        appender.append(event);
+        String result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST, result);
+        
+        appender.setBufferSize(10);
+        
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_SECOND, null );
+        appender.append(event);
+        result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST, result);
+        
+        Thread.sleep(4000);
+        
+        result = FileUtil.readTextFile(new File(TEST_LOG_FILE_FIRST), null);
+        assertEquals(BUFFER_RESULT_FIRST + BUFFER_RESULT_SECOND, result);
+    }
+    
+    /**
+     * 
+     * TestCase for {@link FileAppender#append(LoggingEvent)}
+     * It tests NOOP_OUTPUT_STREAM
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void test_append_noop() throws Exception {
+        File noopFile = new File(TEST_LOG_FILE_NOOP);
+        
+        File mockFile = mock(File.class);
+        when(mockFile.exists()).thenReturn(false);
+        when(mockFile.getAbsoluteFile()).thenReturn(mockFile);
+        when(mockFile.getParentFile()).thenReturn(mockFile);
+        when(mockFile.mkdirs()).thenReturn(true);
+        when(mockFile.createNewFile()).thenThrow(new IOException());
+        
+        whenNew(File.class).withArguments(TEST_LOG_FILE_NOOP).thenReturn(mockFile);
+        event = new LoggingEvent( null, Logger.getLogger( getClass() ), Level.ERROR, BUFFER_RESULT_FIRST, null );
+        appender.append(event);
+        assertFalse(noopFile.exists());
+        
+    }
+    
+    /**
+     * 
+     * Tears down the test
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @After
+    public void tearDown() throws Exception {
+        File testFile = new File(TEST_LOG_FILE_FIRST);
+        if(testFile.exists()) {
+            testFile.delete();
+        }
+        
+        File testFile2 = new File(TEST_LOG_FILE_SECOND);
+        if(testFile2.exists()) {
+            testFile2.delete();
+        }
+        
+        TEST_LAYOUT.setConversionPattern("%m");
+        appender = null;
+    }
+    
+}
diff --git a/org.tizen.common/test/src/org/tizen/common/util/log/GoogleAnalyticAppenderTest.java b/org.tizen.common/test/src/org/tizen/common/util/log/GoogleAnalyticAppenderTest.java
new file mode 100644 (file)
index 0000000..f55adb8
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *  Common
+ *
+ * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
+ *
+ * Contact:
+ * BonYong Lee <bonyong.lee@samsung.com>
+ * Ho Namkoong <ho.namkoong@samsung.com>
+ * 
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+package org.tizen.common.util.log;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.net.HttpURLConnection;
+import java.net.URL;
+
+import static junit.framework.Assert.*;
+
+import org.apache.log4j.Logger;
+import org.apache.log4j.spi.LoggingEvent;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.core.classloader.annotations.PowerMockIgnore;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+import org.slf4j.LoggerFactory;
+import org.tizen.common.util.log.UserLogger.Event;
+import org.tizen.common.util.log.UserLogger.Page;
+import org.tizen.common.util.log.UserLogger.PerformanceInfo;
+
+import static org.powermock.api.mockito.PowerMockito.*;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({GoogleAnalyticAppender.class})
+@PowerMockIgnore(value = {"org.slf4j.*", "org.apache.log4j.*"})
+public class GoogleAnalyticAppenderTest
+{
+    private org.slf4j.Logger logger = LoggerFactory.getLogger(this.getClass());
+    private boolean connected = true;
+    
+    /**
+     * Sets up the test
+     * 
+     * @throws Exception
+     */
+    @Before
+    public void setUp() throws Exception {
+        final URL u = new URL( GoogleAnalyticAppender.URL_GOOGLE_ANALYTIC );
+        HttpURLConnection con = null;
+        try {
+            con = (HttpURLConnection) u.openConnection();
+            con.setDoOutput(true);
+            con.getOutputStream();
+        } catch (IOException e) {
+            connected = false;
+        }
+        finally {
+            if(con != null) {
+            con.disconnect();
+            }
+        }
+    }
+
+    /**
+     * 
+     * TestCase for {@link GoogleAnalyticAppender#append(LoggingEvent)}
+     * 
+     * @author ho.namkoong (ho.namkoong@samsung.com)
+     * 
+     * @throws Exception
+     */
+    @Test
+    public void test_append() throws Exception
+    {
+        if(!connected) {
+            logger.error("Network to the google analytics is not connected");
+            URL mockUrl = mock(URL.class);
+            HttpURLConnection mockCon = mock(HttpURLConnection.class);
+            OutputStream mockOutputStream = mock(OutputStream.class);
+            when(mockCon.getOutputStream()).thenReturn(mockOutputStream);
+            when(mockCon.getResponseCode()).thenReturn(200);
+            when(mockUrl.openConnection()).thenReturn(mockCon);
+            whenNew(URL.class).withArguments(GoogleAnalyticAppender.URL_GOOGLE_ANALYTIC).thenReturn(mockUrl);
+            OutputStreamWriter mockWriter = mock(OutputStreamWriter.class);
+            whenNew(OutputStreamWriter.class).withAnyArguments().thenReturn(mockWriter);
+        }
+        
+        final GoogleAnalyticAppender appender = new GoogleAnalyticAppender(true, true);
+        Logger logger = Logger.getLogger(this.getClass());
+        LoggingEvent event = new LoggingEvent( null, logger, Level.ERROR, "TI", null );
+        appender.append(event);
+        assertTrue(appender.rc >= 200 && appender.rc < 300);
+        
+        event = new LoggingEvent(null, logger, Level.PAGE, new Page("Page category"), null);
+        appender.append(event);
+        assertTrue(appender.rc >= 200 && appender.rc < 300);
+        appender.rc = 0;
+        
+        event = new LoggingEvent(null, logger, Level.EVENT, new Event("Event Category", "Event Action"), null);
+        appender.append(event);
+        assertTrue(appender.rc >= 200 && appender.rc < 300);
+        appender.rc = 0;
+        
+        long start = System.currentTimeMillis();
+        event = new LoggingEvent(null, logger, Level.PERFORM_START, new PerformanceInfo("Performance category", start, 0, "Performance variable"), null);
+        appender.append(event);
+        assertTrue(appender.rc >= 200 && appender.rc < 300);
+        appender.rc = 0;
+        
+        long end = System.currentTimeMillis();
+        event = new LoggingEvent(null, logger, Level.PERFORM_END, new PerformanceInfo("Performance category", start, end, "Performance variable"), null);
+        appender.append(event);
+        assertTrue(appender.rc >= 200 && appender.rc < 300);
+        appender.rc = 0;
+        
+        try {
+            makeException(5);
+        }
+        catch (IllegalStateException e) {
+            event = new LoggingEvent(null, logger, Level.ERROR, "Test Exception", e);
+            appender.append(event);
+            assertTrue(appender.rc >= 200 && appender.rc < 300);
+            appender.rc = 0;
+        }
+    }
+
+    private void makeException(int i) {
+        if(i < 1) {
+            throw new IllegalStateException("Test Exception");
+        }
+        makeException(i-1);
+    }
+    
+    
+
+}
\ No newline at end of file