package de.onyxbits.raccoon; import java.io.File; import javax.swing.SwingUtilities; import org.apache.commons.cli.ParseException; import org.apache.http.client.HttpClient; import com.akdeniz.googleplaycrawler.GooglePlayAPI; import de.onyxbits.raccoon.gui.MainActivity; import de.onyxbits.raccoon.io.Archive; import de.onyxbits.raccoon.rss.Loader; /** * Just the application launcher. * * @author patrick * */ public class App { /** * Version identifier. */ public static final String VERSIONSTRING = "3.7"; /** * Relative path for keeping extension jars in */ public static final String EXTDIR = "ext"; /** * Relative path for keeping archives in (the user is not required to put * archives here, its just the suggested folder). */ public static final String ARCHIVEDIR = "archives"; /** * Relative path to the homedir for caching files. */ public static final String CACHEDIR = "cache"; /** * Relative path, root directory for the app. */ public static final String HOMEDIR = "Raccoon"; /** * Time to live in the cache (1 week). */ public static final long CACHETTL = 1000 * 60 * 60 * 24 * 7; /** * Application Entry * * @param args * @throws ParseException */ public static void main(String[] args) throws ParseException { getDir(HOMEDIR).mkdirs(); getDir(EXTDIR).mkdirs(); getDir(CACHEDIR).mkdirs(); getDir(ARCHIVEDIR).mkdirs(); if (args == null || args.length == 0) { try { long now = System.currentTimeMillis(); File[] lst = getDir(CACHEDIR).listFiles(); for (File f : lst) { if (f.lastModified() < now - CACHETTL) { f.delete(); } } Thread t = new Thread(new Loader()); t.start(); t.join(1500); } catch (InterruptedException e) { e.printStackTrace(); } SwingUtilities.invokeLater(new MainActivity(null)); } else { new CliService(args).run(); } } /** * Query the location of a directory. * * @param which * EXTDIR, ARCHIVEDIR, or HOMEDIR. * @return the file (may or may not exist). */ public static File getDir(String which) { File root = new File(System.getProperty("user.home"), HOMEDIR); if (System.getProperty("raccoon.home") != null) { root = new File(System.getProperty("raccoon.home")); } if (which.equals(HOMEDIR)) { return root; } return new File(root, which); } /** * Utility method for hooking up with Google Play. * * @param archive * The archive from which to take configuration data. * @return a ready to use connection * @throws Exception * if something goes seriously wrong. */ public static synchronized GooglePlayAPI createConnection(Archive archive) throws Exception { String pwd = archive.getPassword(); String uid = archive.getUserId(); String aid = archive.getAndroidId(); String ua = archive.getUserAgent(); GooglePlayAPI ret = new GooglePlayAPI(uid, pwd, aid); if (ua != null) { ret.setUseragent(ua); } HttpClient client = archive.getProxyClient(); if (client != null) { ret.setClient(client); } // I am not quite sure if this method needs to be synchronized, but if so, // this is why: ret.setToken(archive.getAuthToken()); if (ret.getToken() == null) { ret.login(); // Caching the token considerably speeds up talking to the server, but // since multiple downloaders may be active at the same time and the // network may produce all kinds of timing effects, there is a good chance // that two threads would try to connect at the same time. Both see that // the token is not yet available and perform a login. Thread A logs in // first, but B's token returns faster. This results in B's token being // overwritten by A. This is a problem if the tokens are different and // only the latest one is valid. I'm not sure if this is the case, but // serializing connection requests prevents potential trouble. archive.setAuthToken(ret.getToken()); } return ret; } }