1 /* 2 * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package com.sun.java.util.jar.pack; 27 28 import java.beans.PropertyChangeListener; 29 import java.beans.PropertyChangeEvent; 30 import java.io.BufferedInputStream; 31 import java.io.IOException; 32 import java.io.InputStream; 33 import java.io.PrintStream; 34 import java.io.PrintWriter; 35 import java.util.ArrayList; 36 import java.util.Collection; 37 import java.util.Comparator; 38 import java.util.HashMap; 39 import java.util.List; 40 import java.util.Map; 41 import java.util.Properties; 42 import java.util.Set; 43 import java.util.SortedMap; 44 import java.util.TreeMap; 45 import java.util.jar.Pack200; 46 /** 47 * Control block for publishing Pack200 options to the other classes. 48 */ 49 50 final class PropMap implements SortedMap<Object, Object> { 51 private final TreeMap<Object, Object> theMap = new TreeMap<>();; 52 private final List<PropertyChangeListener> listenerList = new ArrayList<>(1); 53 54 void addListener(PropertyChangeListener listener) { 55 listenerList.add(listener); 56 } 57 58 void removeListener(PropertyChangeListener listener) { 59 listenerList.remove(listener); 60 } 61 62 void addListeners(ArrayList<PropertyChangeListener> listeners) { 63 listenerList.addAll(listeners); 64 } 65 66 void removeListeners(ArrayList<PropertyChangeListener> listeners) { 67 listenerList.removeAll(listeners); 68 } 69 70 // Override: 71 public Object put(Object key, Object value) { 72 Object oldValue = theMap.put(key, value); 73 if (value != oldValue && !listenerList.isEmpty()) { 74 // Post the property change event. 75 PropertyChangeEvent event = 76 new PropertyChangeEvent(this, (String) key, 77 oldValue, value); 78 for (PropertyChangeListener listener : listenerList) { 79 listener.propertyChange(event); 80 } 81 } 82 return oldValue; 83 } 84 85 // All this other stuff is private to the current package. 86 // Outide clients of Pack200 do not need to use it; they can 87 // get by with generic SortedMap functionality. 88 private static Map<Object, Object> defaultProps; 89 static { 90 Properties props = new Properties(); 91 92 // Allow implementation selected via -Dpack.disable.native=true 93 props.put(Utils.DEBUG_DISABLE_NATIVE, 94 String.valueOf(Boolean.getBoolean(Utils.DEBUG_DISABLE_NATIVE))); 95 96 // Set the DEBUG_VERBOSE from system 97 props.put(Utils.DEBUG_VERBOSE, 98 String.valueOf(Integer.getInteger(Utils.DEBUG_VERBOSE,0))); 99 100 // Set the PACK_TIMEZONE_NO_UTC 101 props.put(Utils.PACK_DEFAULT_TIMEZONE, 102 String.valueOf(Boolean.getBoolean(Utils.PACK_DEFAULT_TIMEZONE))); 103 104 // The segment size is unlimited 105 props.put(Pack200.Packer.SEGMENT_LIMIT, "-1"); 106 107 // Preserve file ordering by default. 108 props.put(Pack200.Packer.KEEP_FILE_ORDER, Pack200.Packer.TRUE); 109 110 // Preserve all modification times by default. 111 props.put(Pack200.Packer.MODIFICATION_TIME, Pack200.Packer.KEEP); 112 113 // Preserve deflation hints by default. 114 props.put(Pack200.Packer.DEFLATE_HINT, Pack200.Packer.KEEP); 115 116 // Pass through files with unrecognized attributes by default. 117 props.put(Pack200.Packer.UNKNOWN_ATTRIBUTE, Pack200.Packer.PASS); 118 119 // Default effort is 5, midway between 1 and 9. 120 props.put(Pack200.Packer.EFFORT, "5"); 121 122 // Define certain attribute layouts by default. 123 // Do this after the previous props are put in place, 124 // to allow override if necessary. 125 InputStream propStr = null; 126 try { 127 String propFile = "intrinsic.properties"; 128 propStr = PackerImpl.class.getResourceAsStream(propFile); 129 props.load(new BufferedInputStream(propStr)); 130 for (Map.Entry<Object, Object> e : props.entrySet()) { 131 String key = (String) e.getKey(); 132 String val = (String) e.getValue(); 133 if (key.startsWith("attribute.")) { 134 e.setValue(Attribute.normalizeLayoutString(val)); 135 } 136 } 137 } catch (IOException ee) { 138 throw new RuntimeException(ee); 139 } finally { 140 try { 141 if (propStr != null) { 142 propStr.close(); 143 } 144 } catch (IOException ignore) {} 145 } 146 147 defaultProps = (new HashMap<>(props)); // shrink to fit 148 } 149 150 PropMap() { 151 theMap.putAll(defaultProps); 152 } 153 154 // Return a view of this map which includes only properties 155 // that begin with the given prefix. This is easy because 156 // the map is sorted, and has a subMap accessor. 157 SortedMap<Object, Object> prefixMap(String prefix) { 158 int len = prefix.length(); 159 if (len == 0) 160 return this; 161 char nextch = (char)(prefix.charAt(len-1) + 1); 162 String limit = prefix.substring(0, len-1)+nextch; 163 //System.out.println(prefix+" => "+subMap(prefix, limit)); 164 return subMap(prefix, limit); 165 } 166 167 String getProperty(String s) { 168 return (String) get(s); 169 } 170 String getProperty(String s, String defaultVal) { 171 String val = getProperty(s); 172 if (val == null) 173 return defaultVal; 174 return val; 175 } 176 String setProperty(String s, String val) { 177 return (String) put(s, val); 178 } 179 180 // Get sequence of props for "prefix", and "prefix.*". 181 List getProperties(String prefix) { 182 Collection<Object> values = prefixMap(prefix).values(); 183 List<Object> res = new ArrayList<>(values.size()); 184 res.addAll(values); 185 while (res.remove(null)); 186 return res; 187 } 188 189 private boolean toBoolean(String val) { 190 return Boolean.valueOf(val).booleanValue(); 191 } 192 boolean getBoolean(String s) { 193 return toBoolean(getProperty(s)); 194 } 195 boolean setBoolean(String s, boolean val) { 196 return toBoolean(setProperty(s, String.valueOf(val))); 197 } 198 199 int toInteger(String val) { 200 if (val == null) return 0; 201 if (Pack200.Packer.TRUE.equals(val)) return 1; 202 if (Pack200.Packer.FALSE.equals(val)) return 0; 203 return Integer.parseInt(val); 204 } 205 int getInteger(String s) { 206 return toInteger(getProperty(s)); 207 } 208 int setInteger(String s, int val) { 209 return toInteger(setProperty(s, String.valueOf(val))); 210 } 211 212 long toLong(String val) { 213 try { 214 return val == null ? 0 : Long.parseLong(val); 215 } catch (java.lang.NumberFormatException nfe) { 216 throw new IllegalArgumentException("Invalid value"); 217 } 218 } 219 long getLong(String s) { 220 return toLong(getProperty(s)); 221 } 222 long setLong(String s, long val) { 223 return toLong(setProperty(s, String.valueOf(val))); 224 } 225 226 int getTime(String s) { 227 String sval = getProperty(s, "0"); 228 if (Utils.NOW.equals(sval)) { 229 return (int)((System.currentTimeMillis()+500)/1000); 230 } 231 long lval = toLong(sval); 232 final long recentSecondCount = 1000000000; 233 234 if (lval < recentSecondCount*10 && !"0".equals(sval)) 235 Utils.log.warning("Supplied modtime appears to be seconds rather than milliseconds: "+sval); 236 237 return (int)((lval+500)/1000); 238 } 239 240 void list(PrintStream out) { 241 PrintWriter outw = new PrintWriter(out); 242 list(outw); 243 outw.flush(); 244 } 245 void list(PrintWriter out) { 246 out.println("#"+Utils.PACK_ZIP_ARCHIVE_MARKER_COMMENT+"["); 247 Set defaults = defaultProps.entrySet(); 248 for (Map.Entry e : theMap.entrySet()) { 249 if (defaults.contains(e)) continue; 250 out.println(" " + e.getKey() + " = " + e.getValue()); 251 } 252 out.println("#]"); 253 } 254 255 @Override 256 public int size() { 257 return theMap.size(); 258 } 259 260 @Override 261 public boolean isEmpty() { 262 return theMap.isEmpty(); 263 } 264 265 @Override 266 public boolean containsKey(Object key) { 267 return theMap.containsKey(key); 268 } 269 270 @Override 271 public boolean containsValue(Object value) { 272 return theMap.containsValue(value); 273 } 274 275 @Override 276 public Object get(Object key) { 277 return theMap.get(key); 278 } 279 280 @Override 281 public Object remove(Object key) { 282 return theMap.remove(key); 283 } 284 285 @Override 286 @SuppressWarnings("unchecked") 287 public void putAll(Map m) { 288 theMap.putAll(m); 289 } 290 291 @Override 292 public void clear() { 293 theMap.clear(); 294 } 295 296 @Override 297 public Set<Object> keySet() { 298 return theMap.keySet(); 299 } 300 301 @Override 302 public Collection<Object> values() { 303 return theMap.values(); 304 } 305 306 @Override 307 public Set<Map.Entry<Object, Object>> entrySet() { 308 return theMap.entrySet(); 309 } 310 311 @Override 312 @SuppressWarnings("unchecked") 313 public Comparator<Object> comparator() { 314 return (Comparator<Object>) theMap.comparator(); 315 } 316 317 @Override 318 public SortedMap<Object, Object> subMap(Object fromKey, Object toKey) { 319 return theMap.subMap(fromKey, toKey); 320 } 321 322 @Override 323 public SortedMap<Object, Object> headMap(Object toKey) { 324 return theMap.headMap(toKey); 325 } 326 327 @Override 328 public SortedMap<Object, Object> tailMap(Object fromKey) { 329 return theMap.tailMap(fromKey); 330 } 331 332 @Override 333 public Object firstKey() { 334 return theMap.firstKey(); 335 } 336 337 @Override 338 public Object lastKey() { 339 return theMap.lastKey(); 340 } 341 }