/*
* Copyright 2010-2015 Institut Pasteur.
*
* This file is part of Icy.
*
* Icy is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* Icy is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with Icy. If not, see <http://www.gnu.org/licenses/>.
*/
package icy.system.audit;
import icy.file.FileUtil;
import icy.gui.frame.progress.CancelableProgressFrame;
import icy.gui.main.MainFrame;
import icy.main.Icy;
import icy.network.NetworkUtil;
import icy.plugin.abstract_.Plugin;
import icy.preferences.ApplicationPreferences;
import icy.preferences.GeneralPreferences;
import icy.preferences.XMLPreferences;
import icy.system.IcyExceptionHandler;
import icy.system.SystemUtil;
import icy.system.thread.ThreadUtil;
import icy.util.StringUtil;
import icy.util.XMLUtil;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
/**
* General audit tools class.
*
* @author Stephane
*/
public class Audit
{
// network URL
static final String URL_REGISTER = NetworkUtil.WEBSITE_URL + "register/registerClient.php?";
static final String URL_LINK_USER = NetworkUtil.WEBSITE_URL + "register/linkUser.php?";
static final String URL_GET_USER_INFO = NetworkUtil.WEBSITE_URL + "register/getLinkedUserInfo.php?";
static final String URL_AUDIT_VERSION = NetworkUtil.WEBSITE_URL + "register/auditVersion.php?";
static final String URL_AUDIT_PLUGIN = NetworkUtil.WEBSITE_URL + "register/auditPlugin.php?";
// prefs & network id
static final String ID_REQUEST = "requestId";
static final String ID_ACTION = "action";
static final String ID_ICY_ID = "IcyId";
static final String ID_CLIENT_ARCH = "clientArch";
static final String ID_CLIENT_ID = "clientId";
static final String ID_CLIENT_VERSION = "clientVersion";
static final String ID_CLIENT_CPUNUMBER = "clientCpuNumber";
static final String ID_CLIENT_TOTAL_MEMORY = "clientTotalMemory";
static final String ID_CLIENT_MAXJAVA_MEMORY = "clientMaxJavaMemory";
static final String ID_JAVA_NAME = "javaName";
static final String ID_JAVA_VERSION = "javaVersion";
static final String ID_JAVA_ARCH = "javaArch";
static final String ID_LAST_UPLOAD_DATE = "lastUploadDate";
// xml id
static final String XMLID_CLIENT_ID_REQUESTED = "client_id_requested";
static final String XMLID_USER_LOGIN = "user_login";
static final String XMLID_USER_NAME = "user_name";
// directly use application preferences here
static XMLPreferences prefs;
static AuditStorage storage;
private static boolean initialized = false;
private static boolean auditDone;
/**
* Audit process on application start.<br>
* Check id, register...
*/
public static synchronized void prepare()
{
if (initialized)
return;
// get preferences
prefs = ApplicationPreferences.getPreferences();
// probably a new installation --> need to reset id
if (needToResetId())
{
// reset user info if needed
unlinkUser();
// reset id
ApplicationPreferences.setId(-1);
}
// store current infos
storeInfos();
// init audit storage
storage = new AuditStorage();
final int id = ApplicationPreferences.getId();
// id assigned ?
if (id != -1)
{
final long currentTime = System.currentTimeMillis();
final long dayInterval = 1000 * 60 * 60 * 24;
// upload each 24 hours
if (currentTime > (prefs.getLong(ID_LAST_UPLOAD_DATE, 0L) + dayInterval))
{
// save upload time whatever happened
prefs.putLong(ID_LAST_UPLOAD_DATE, System.currentTimeMillis());
// do that in background as it can take sometime if website does not reply...
ThreadUtil.bgRun(new Runnable()
{
@Override
public void run()
{
// upload usage statistics
storage.upload(id);
}
});
}
}
initialized = true;
auditDone = false;
}
/**
* Audit process on network connection
*/
public static void onConnect()
{
prepare();
if (!auditDone)
processIdAudit();
updateUserLink();
final MainFrame frame = Icy.getMainInterface().getMainFrame();
// refresh user infos
if (frame != null)
frame.refreshUserInfos();
}
/**
* Save audit data
*/
public static void save()
{
// save audit data
if (initialized)
storage.save();
}
/**
* Plugin launched event audit
*/
public static void pluginLaunched(Plugin plugin)
{
prepare();
storage.pluginLaunched(plugin);
}
/**
* Plugin instancied event audit
*/
public static void pluginInstancied(Plugin plugin)
{
prepare();
storage.pluginInstancied(plugin);
}
/**
* Returns <code>true</code> if we need to reset the internal id (usually mean new installation)
*/
private static boolean needToResetId()
{
if (!StringUtil.equals(ApplicationPreferences.getOs(), SystemUtil.getOSArchIdString()))
return true;
final int cpu = prefs.getInt(ID_CLIENT_CPUNUMBER, 0);
final long mem = prefs.getLong(ID_CLIENT_TOTAL_MEMORY, 0);
final String appFolder = ApplicationPreferences.getAppFolder();
// ignore difference on first launch else it will regenerate id for everyone
if ((cpu != 0) && (cpu != SystemUtil.getNumberOfCPUs()))
return true;
if ((mem != 0) && (mem != SystemUtil.getTotalMemory()))
return true;
if (!StringUtil.isEmpty(appFolder) && !StringUtil.equals(appFolder, FileUtil.APPLICATION_DIRECTORY))
return true;
return false;
}
/**
* Store system and application informations in preferences
*/
private static void storeInfos()
{
ApplicationPreferences.setOs(SystemUtil.getOSArchIdString());
prefs.putInt(ID_CLIENT_CPUNUMBER, SystemUtil.getNumberOfCPUs());
prefs.putLong(ID_CLIENT_TOTAL_MEMORY, SystemUtil.getTotalMemory());
ApplicationPreferences.setAppFolder(FileUtil.APPLICATION_DIRECTORY);
}
private static void processIdAudit()
{
final Map<String, String> values = new HashMap<String, String>();
final int id = ApplicationPreferences.getId();
values.put(ID_CLIENT_ARCH, SystemUtil.getOSArchIdString());
values.put(ID_CLIENT_VERSION, Icy.version.toString());
// need to register
if (id == -1)
{
// ask for registration
values.put(ID_REQUEST, "1");
final Document doc = XMLUtil.loadDocument(URL_REGISTER + NetworkUtil.getContentString(values));
if (doc != null)
{
final Node root = XMLUtil.getRootElement(doc);
final int newId = XMLUtil.getElementIntValue(root, XMLID_CLIENT_ID_REQUESTED, -1);
// valid id --> save it
if (newId != -1)
ApplicationPreferences.setId(newId);
}
}
else
{
// just audit infos
values.put(ID_CLIENT_ID, Integer.toString(id));
values.put(ID_CLIENT_CPUNUMBER, Integer.toString(SystemUtil.getNumberOfCPUs()));
values.put(ID_CLIENT_TOTAL_MEMORY, Long.toString(SystemUtil.getTotalMemory() / 10485760L));
values.put(ID_CLIENT_MAXJAVA_MEMORY, Long.toString(SystemUtil.getJavaMaxMemory() / 10485760L));
values.put(ID_JAVA_NAME, SystemUtil.getJavaName());
values.put(ID_JAVA_VERSION, SystemUtil.getJavaVersion());
values.put(ID_JAVA_ARCH, Integer.toString(SystemUtil.getJavaArchDataModel()));
try
{
NetworkUtil.postData(URL_AUDIT_VERSION, values);
}
catch (IOException e)
{
// silent fail...
// IcyExceptionHandler.showErrorMessage(e, false, false);
}
}
auditDone = true;
}
private static Map<String, String> getIdParam()
{
final int id = ApplicationPreferences.getId();
// id ok ?
if (id != -1)
{
final Map<String, String> values = new HashMap<String, String>();
// set id
values.put(ID_ICY_ID, Integer.toString(id));
return values;
}
return null;
}
public static void updateUserLink()
{
final Map<String, String> params = getIdParam();
// id param ok ?
if (params != null)
{
// and retrieve user infos
final Document doc = XMLUtil.loadDocument(URL_GET_USER_INFO + NetworkUtil.getContentString(params));
if (doc != null)
{
final Node root = XMLUtil.getRootElement(doc);
// set attached user login and name
GeneralPreferences.setUserLogin(XMLUtil.getElementValue(root, XMLID_USER_LOGIN, ""));
GeneralPreferences.setUserName(XMLUtil.getElementValue(root, XMLID_USER_NAME, ""));
}
}
}
public static boolean isUserLinked()
{
return !StringUtil.isEmpty(GeneralPreferences.getUserLogin());
}
public static void linkUser()
{
final int id = ApplicationPreferences.getId();
// id ok ?
if (id != -1)
{
// launch browser with link identity request
NetworkUtil.openBrowser(URL_LINK_USER + ID_ICY_ID + "=" + id + "&" + ID_ACTION + "=link");
if (!Icy.getMainInterface().isHeadLess())
{
// display linking in progress
new Thread(new Runnable()
{
@Override
public void run()
{
final CancelableProgressFrame waitFrame = new CancelableProgressFrame(
"Waiting for user to link account...");
while (!Thread.interrupted() && !waitFrame.isCancelRequested())
{
try
{
Thread.sleep(1000);
updateUserLink();
// user linked !
if (isUserLinked())
{
// stop wait
waitFrame.cancel();
// refresh user infos
final MainFrame frame = Icy.getMainInterface().getMainFrame();
if (frame != null)
frame.refreshUserInfos();
}
}
catch (InterruptedException e)
{
waitFrame.cancel();
}
}
// close wait frame
waitFrame.close();
}
}).start();
}
}
}
public static void unlinkUser()
{
final Map<String, String> params = getIdParam();
// id param ok ?
if (params != null)
{
// do that in background as it can take sometime...
ThreadUtil.bgRun(new Runnable()
{
@Override
public void run()
{
// set action
params.put(ID_ACTION, "unlink");
try
{
// and post
NetworkUtil.postData(URL_LINK_USER, params);
}
catch (IOException e)
{
// can't unlink on web site, not a big deal...
System.err.print("Warning: cannot unlink online user infos.");
IcyExceptionHandler.showErrorMessage(e, false, false);
}
}
});
}
// reset attached user login and name
GeneralPreferences.setUserLogin("");
GeneralPreferences.setUserName("");
}
}