/* * Copyright 2011 Uwe Krueger. * * 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. */ package com.mandelsoft.mand; import com.mandelsoft.io.AbstractFile; import java.io.BufferedInputStream; import java.io.File; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; import java.security.AccessControlException; import java.util.Properties; import java.util.Set; import java.util.Stack; import com.mandelsoft.util.Utils; /** * * @author Uwe Krueger */ public class Settings { static public final String ENV_MANDEL_HOME="MANDEL_HOME"; static public final String ENV_HOME="HOME"; static public final String MANDEL_SETTINGS=".mandtool"; static public final String MANDEL_HOME="home"; static public final String MANDEL_DIR="dir"; static public final String BASE="base"; static public final String PATH="path"; static public final String ADDITIONAL_PATH="path.additional"; static public final String AUTORESCAN="autorescan"; static public final String PROXY="proxy"; static public final String USER="username"; static public final String SITE="sitename"; static public final String HOMEPAGE="homepage"; static public final String COPYRIGHT="copyright"; static public final String BACKUP_PATH="path.backup"; static public final String SAVE_PATH="path.save"; static public final String BITMAP_SAVE_PATH="path.bitmap.save"; static public final String INCOMPLETE_SAVE_PATH="path.incomplete.save"; static public final String INCOMPLETE_BACKUP_PATH="path.incomplete.backup"; static public final String INFO_PRIO_PATH="path.info.prio"; static public final String INFO_SAVE_PATH="path.info.save"; static public final String INFO_BACKUP_PATH="path.info.backup"; static public final String RASTER_PATH="path.raster"; static public final String RASTER_SEEN_PATH="path.raster.seen"; static public final String VARIANT_SEEN_PATH="path.variant.seen"; static public final String RASTER_SAVE_PATH="path.raster.save"; static public final String AREACOLMAP_PATH="path.areacolormap"; static public final String AREACOLMAP_SAVE_PATH="path.areacolormap.save"; static public final String AREACOLMAP_BACKUP_PATH="path.areacolormap.backup"; static public final String RASTER_BACKUP_PATH="path.raster.backup"; static public final String VARIANT_SAVE_PATH="path.variant.save"; static public final String RASTERIMAGE_SAVE_PATH="path.rasterimage.save"; static public final String RASTERIMAGE_BACKUP_PATH="path.rasterimage.backup"; static public final String IMAGE_SAVE_PATH="path.image.save"; static public final String INFO_CLEANUP="cleanup.info"; static public final String RASTER_CLEANUP="cleanup.raster"; static public final String RASTERIMAGE_CLEANUP="cleanup.rasterimage"; static public final String COLORMAP_SAVE_PATH="path.colormap.save"; static public final String COLORMAP_PATH="path.colormap"; static public final String FAVORITES="favorites"; static public final String AREAS="areas"; static public final String TODO="todo"; static public final String REFINEMENTS="refinements"; static public final String SEEN="seen"; static public final String LINKS="links"; static public final String COLORS="colors"; static public final String TAGS="tags"; static public final String USERLIST_PATH="path.lists"; static public final String LIST_SHORTCUTS="shortcuts.lists"; static public final String DEFCOLORMAP="colormap.default"; static public final String NESTED="path.base"; static public final String ALIASES="aliases"; static public final String COLORMAP_CACHE_SIZE="cache.colormaps"; //////////////////////////////////////////////////////////////////////// // factory //////////////////////////////////////////////////////////////////////// static public Settings getSettings() throws IOException { return getSettings(new File(".")); } static public Settings getSettings(File dir) throws IOException { return getSettings(AbstractFile.Factory.create(dir)); } static public Settings getSettings(AbstractFile dir) throws IOException { Settings ms=new Settings(dir.isFile()); String prop="current.dir"; System.out.println("*** settings for "+dir); if (dir.isFile()) { File f=new File(dir.getFile(), MANDEL_SETTINGS); ms.setProperty(prop, dir.toString()); if (!f.exists()||!f.isFile()) { ms=handle(System.getenv(ENV_MANDEL_HOME), ms, MANDEL_HOME, true); ms=handle(System.getenv(ENV_HOME), ms, "user.home", true); } else ms=handle(dir, ms, null, true); } else ms=handle(dir,ms,prop, true); String b=ms.getProperty(BASE); if (!Utils.isEmpty(b)) { System.out.println("base is "+b); Settings base=getSettings(AbstractFile.Factory.create(b, dir.getProxy(), dir.isFile())); ms=handle(dir,base,null, false); ms.remove(BASE); } return ms; } ////////////////////////////////////////////////////////////////////////// static private Settings handle(String dir, Settings parent, String prop, boolean mandel) throws IOException { if (dir!=null) { return handle(new File(dir),parent,prop, mandel); } return parent; } static private Settings handle(File dir, Settings parent, String prop, boolean mandel) throws IOException { if (dir!=null) { return handle(AbstractFile.Factory.create(dir),parent,prop, mandel); } return parent; } static private Settings handle(AbstractFile d, Settings parent, String prop, boolean mandel) throws IOException { if (d!=null) { if (!d.isFile() || (d.getFile().exists() && d.getFile().isDirectory())) { if (prop!=null) parent.setProperty(prop, d.toString()); AbstractFile m=d.getSub(MANDEL_SETTINGS); if (!m.isFile() || (m.getFile().exists() && m.getFile().isFile())) { if (mandel) { parent.setProperty(MANDEL_DIR, d.toString()); } parent=new Settings(m, parent); } } } return parent; } ////////////////////////////////////////////////////////////////////////// // property evaluation ////////////////////////////////////////////////////////////////////////// private void process() throws IOException { if (parent!=null) { for (String n:parent.propertyNames()) { if (!raw.containsKey(n)) { raw.setProperty(n,parent.raw.getProperty(n)); } } } for (String n:propertyNames()) { props.setProperty(n, process(n,new Stack<String>())); // System.out.println(n+": "+raw.getProperty(n)+" -> "+props.getProperty(n)); } } private String process(String n, Stack<String> stack) throws IOException { String v=props.getProperty(n); if (!Utils.isEmpty(v)) return v; v=raw.getProperty(n); if (Utils.isEmpty(v)) return v; StringBuilder sb=new StringBuilder(); if (stack.contains(n)) { throw new IOException("recursion found for "+n+": "+stack); } stack.push(n); try { int is=0; int ix; while ((ix=v.indexOf("${",is))>=0) { sb.append(v.substring(is, ix)); int ie=v.indexOf("}", ix); if (ie>=0) { String name=v.substring(ix+2, ie); ix=ix+1; String subst; if (name.equals(n)) { if (parent==null) subst=""; else subst=parent.getProperty(n); } else { subst=process(name, stack); if (!Utils.isEmpty(subst)) props.setProperty(name,subst); } if (!Utils.isEmpty(subst)) sb.append(subst); is=ie+1; } else { sb.append("${"); is=ix+2; } } sb.append(v.substring(is)); } finally { stack.pop(); } return sb.toString(); } //////////////////////////////////////////////////////////////////////// // Settings //////////////////////////////////////////////////////////////////////// private Settings parent; private Properties raw=new Properties(); private Properties props=new Properties(); private boolean local; public Settings(boolean local) { this.parent=null; this.local=local; System.out.println("local="+local); // set defaults raw.setProperty("mandtool.root",MandelName.ROOT_NAME); try { raw.setProperty(USER,System.getProperty("user.name")); } catch (AccessControlException ex) { } InetAddress addr; try { addr=InetAddress.getLocalHost(); String host=addr==null?null:addr.getCanonicalHostName(); if (host!=null) raw.setProperty(SITE,host); } catch (UnknownHostException ex) { } raw.setProperty(FAVORITES, "${dir}/favorites"); raw.setProperty(COLORS, "${dir}/colors"); raw.setProperty(TAGS, "${dir}/tags"); raw.setProperty(AREAS, "${dir}/areas"); raw.setProperty(REFINEMENTS, "${dir}/refine"); if (local) { raw.setProperty(TODO, "${dir}/todo"); raw.setProperty(LINKS, "${dir}/links"); raw.setProperty(SEEN, "${dir}/seen"); raw.setProperty(BITMAP_SAVE_PATH, "${dir}/bitmaps"); raw.setProperty(INCOMPLETE_SAVE_PATH, "${dir}/incomplete"); raw.setProperty(RASTERIMAGE_BACKUP_PATH, "${"+BACKUP_PATH+"}"); raw.setProperty(RASTER_BACKUP_PATH, "${"+BACKUP_PATH+"}"); raw.setProperty(INFO_BACKUP_PATH, "${"+BACKUP_PATH+"}"); raw.setProperty(AREACOLMAP_BACKUP_PATH, "${"+BACKUP_PATH+"}"); raw.setProperty(INCOMPLETE_BACKUP_PATH, "${"+BACKUP_PATH+"}"); } raw.setProperty(IMAGE_SAVE_PATH, "${"+SAVE_PATH+"}"); raw.setProperty(RASTER_SAVE_PATH, "${"+SAVE_PATH+"}"); raw.setProperty(AREACOLMAP_SAVE_PATH, "${"+SAVE_PATH+"}"); raw.setProperty(RASTER_PATH, "${"+RASTER_SAVE_PATH+"};"+ "${"+RASTER_SEEN_PATH+"};"+ "${"+VARIANT_SEEN_PATH+"}"); raw.setProperty(RASTERIMAGE_SAVE_PATH, "${"+SAVE_PATH+"}"); raw.setProperty(INFO_SAVE_PATH, "${"+SAVE_PATH+"}"); raw.setProperty(VARIANT_SEEN_PATH, "${"+VARIANT_SAVE_PATH+"}"); raw.setProperty(PATH, "${"+IMAGE_SAVE_PATH+"};${"+ RASTERIMAGE_SAVE_PATH+"};${"+ RASTER_SAVE_PATH+"};${"+ RASTER_SEEN_PATH+"};${"+ VARIANT_SEEN_PATH+"};${"+ RASTER_PATH+"};${"+ ADDITIONAL_PATH+"};${"+ AREACOLMAP_PATH+"};${"+ AREACOLMAP_SAVE_PATH+"};${"+ INFO_PRIO_PATH+"};${"+ INFO_SAVE_PATH+"}"); raw.setProperty(COLORMAP_SAVE_PATH, "${"+SAVE_PATH+"}"); raw.setProperty(COLORMAP_PATH, "${"+COLORMAP_SAVE_PATH+"}"); try { process(); } catch (IOException ex) { } } public Settings(AbstractFile file, Settings parent) throws IOException { if (parent!=null) local=parent.local; else local=file.isFile(); this.parent=parent; BufferedInputStream is=null; try { System.out.println("reading mandel settings URL "+file+"..."); raw.load(is=new BufferedInputStream(file.getInputStream())); } finally { if (is!=null) is.close(); } process(); } public boolean isLocal() { return local; } public Set<String> propertyNames() { return raw.stringPropertyNames(); } public synchronized Object setProperty(String key, String value) { raw.setProperty(key, value); String old=getProperty(key); try { process(); } catch (IOException ex) { return null; } return old; } public String getProperty(String key, String defaultValue) { return props.getProperty(key, defaultValue); } public String getProperty(String key) { return props.getProperty(key); } public boolean getSwitch(String key, boolean def) { String p=getProperty(key); if (!Utils.isEmpty(p)) { p=p.toLowerCase(); if (p.equals("true") || p.equals("on") || p.equals("yes")) { def=true; } else { if (p.equals("false") || p.equals("off") || p.equals("no")) def=false; } } return def; } public boolean contains(String p) { return raw.contains(p); } public boolean remove(String p) { if (raw.contains(p)) { raw.remove(p); props.remove(p); return true; } return false; } //////////////////////////////////////////////////////////////////////// // main //////////////////////////////////////////////////////////////////////// static private void Error(String msg) { System.err.println(msg); System.exit(2); } static public void main(String[] args) { try { Settings ms=Settings.getSettings(); for (String s:ms.propertyNames()) { System.out.println(s+"="+ms.getProperty(s)); } } catch (IOException ex) { Error("cannot read settings: "+ex); } } }