1 /*
   2  * Copyright (c) 2011, 2018, 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 javafx.css.converter;
  27 
  28 import com.sun.javafx.util.Logging;
  29 import javafx.css.ParsedValue;
  30 import javafx.css.StyleConverter;
  31 import javafx.scene.text.Font;
  32 import com.sun.javafx.logging.PlatformLogger;
  33 import com.sun.javafx.logging.PlatformLogger.Level;
  34 
  35 import java.io.DataInputStream;
  36 import java.io.DataOutputStream;
  37 import java.io.IOException;
  38 import java.util.HashMap;
  39 import java.util.Locale;
  40 import java.util.Map;
  41 
  42 /**
  43  * @since 9
  44  */
  45 public final class EnumConverter<E extends Enum<E>> extends StyleConverter<String, E> {
  46 
  47     // package for unit testing
  48     final Class<E> enumClass;
  49 
  50     public EnumConverter(Class<E> enumClass) {
  51         this.enumClass = enumClass;
  52     }
  53 
  54     @Override
  55     public E convert(ParsedValue<String, E> value, Font not_used) {
  56         if (enumClass == null) {
  57             return null;
  58         }
  59         String string = value.getValue();
  60         final int dotPos = string.lastIndexOf('.');
  61         if (dotPos > -1) {
  62             string = string.substring(dotPos + 1);
  63         }
  64         try {
  65             string = string.replace('-', '_');
  66             return Enum.valueOf(enumClass, string.toUpperCase(Locale.ROOT));
  67         } catch (IllegalArgumentException e) {
  68             // may throw another IllegalArgumentException
  69             return Enum.valueOf(enumClass, string);
  70         }
  71     }
  72 
  73     @Override
  74     public void writeBinary(DataOutputStream os, StringStore sstore) throws IOException {
  75         super.writeBinary(os,sstore);
  76         String ename = enumClass.getName();
  77         int index = sstore.addString(ename);
  78         os.writeShort(index);
  79     }
  80 
  81 
  82     public static StyleConverter<?,?> readBinary(DataInputStream is, String[] strings)
  83             throws IOException {
  84 
  85         short index = is.readShort();
  86         String ename = 0 <= index && index <= strings.length ? strings[index] : null;
  87 
  88         if (ename == null || ename.isEmpty()) return null;
  89 
  90         if (converters == null || converters.containsKey(ename) == false) {
  91             StyleConverter<?,?> converter = getInstance(ename);
  92 
  93             if (converter == null) {
  94                 final PlatformLogger logger = Logging.getCSSLogger();
  95                 if (logger.isLoggable(Level.SEVERE)) {
  96                     logger.severe("could not deserialize EnumConverter for " + ename);
  97                 }
  98             }
  99 
 100             if (converters == null) converters = new HashMap<String,StyleConverter<?,?>>();
 101             converters.put(ename, converter);
 102             return converter;
 103         }
 104         return converters.get(ename);
 105     }
 106 
 107     private static Map<String,StyleConverter<?,?>> converters;
 108 
 109     // package for unit testing
 110     static public StyleConverter<?,?> getInstance(final String ename) {
 111 
 112         StyleConverter<?,?> converter = null;
 113 
 114         switch (ename) {
 115         case "com.sun.javafx.cursor.CursorType" :
 116             converter = new EnumConverter<com.sun.javafx.cursor.CursorType>(com.sun.javafx.cursor.CursorType.class);
 117             break;
 118         case "javafx.scene.layout.BackgroundRepeat" :
 119         case "com.sun.javafx.scene.layout.region.Repeat" :
 120             converter = new EnumConverter<javafx.scene.layout.BackgroundRepeat>(javafx.scene.layout.BackgroundRepeat.class);
 121             break;
 122         case "javafx.geometry.HPos" :
 123             converter = new EnumConverter<javafx.geometry.HPos>(javafx.geometry.HPos.class);
 124             break;
 125         case "javafx.geometry.Orientation" :
 126             converter = new EnumConverter<javafx.geometry.Orientation>(javafx.geometry.Orientation.class);
 127             break;
 128         case "javafx.geometry.Pos" :
 129             converter = new EnumConverter<javafx.geometry.Pos>(javafx.geometry.Pos.class);
 130             break;
 131         case "javafx.geometry.Side" :
 132             converter = new EnumConverter<javafx.geometry.Side>(javafx.geometry.Side.class);
 133             break;
 134         case "javafx.geometry.VPos" :
 135             converter = new EnumConverter<javafx.geometry.VPos>(javafx.geometry.VPos.class);
 136             break;
 137         case "javafx.scene.effect.BlendMode" :
 138             converter = new EnumConverter<javafx.scene.effect.BlendMode>(javafx.scene.effect.BlendMode.class);
 139             break;
 140         case "javafx.scene.effect.BlurType" :
 141             converter = new EnumConverter<javafx.scene.effect.BlurType>(javafx.scene.effect.BlurType.class);
 142             break;
 143         case "javafx.scene.paint.CycleMethod" :
 144             converter = new EnumConverter<javafx.scene.paint.CycleMethod>(javafx.scene.paint.CycleMethod.class);
 145             break;
 146         case "javafx.scene.shape.ArcType" :
 147             converter = new EnumConverter<javafx.scene.shape.ArcType>(javafx.scene.shape.ArcType.class);
 148             break;
 149         case "javafx.scene.shape.StrokeLineCap" :
 150             converter = new EnumConverter<javafx.scene.shape.StrokeLineCap>(javafx.scene.shape.StrokeLineCap.class);
 151             break;
 152         case "javafx.scene.shape.StrokeLineJoin" :
 153             converter = new EnumConverter<javafx.scene.shape.StrokeLineJoin>(javafx.scene.shape.StrokeLineJoin.class);
 154             break;
 155         case "javafx.scene.shape.StrokeType" :
 156             converter = new EnumConverter<javafx.scene.shape.StrokeType>(javafx.scene.shape.StrokeType.class);
 157             break;
 158         case "javafx.scene.text.FontPosture" :
 159             converter = new EnumConverter<javafx.scene.text.FontPosture>(javafx.scene.text.FontPosture.class);
 160             break;
 161         case "javafx.scene.text.FontSmoothingType" :
 162             converter = new EnumConverter<javafx.scene.text.FontSmoothingType>(javafx.scene.text.FontSmoothingType.class);
 163             break;
 164         case "javafx.scene.text.FontWeight" :
 165             converter = new EnumConverter<javafx.scene.text.FontWeight>(javafx.scene.text.FontWeight.class);
 166             break;
 167         case "javafx.scene.text.TextAlignment" :
 168             converter = new EnumConverter<javafx.scene.text.TextAlignment>(javafx.scene.text.TextAlignment.class);
 169             break;
 170 
 171         default :
 172             //
 173             // Enum types that are not in the javafx-ui-common source tree.
 174             //
 175             // Because the parser doesn't explicitly know about these enums
 176             // outside of the javafx-ui-common package, I don't expect these
 177             // EnumConverters to have been persisted. For example, the
 178             // -fx-text-overrun and -fx-content-display properties, will yield
 179             // a ParsedValue<String,String> with a null converter.
 180             //
 181             // If assertions are disabled, then null is returned. The StyleHelper
 182             // code will use the StyleableProperty's converter in this case.
 183             //
 184             assert false : "EnumConverter<"+ ename + "> not expected";
 185 
 186             final PlatformLogger logger = Logging.getCSSLogger();
 187             if (logger.isLoggable(Level.SEVERE)) {
 188                 logger.severe("EnumConverter : converter Class is null for : "+ename);
 189             }
 190             break;
 191         }
 192 
 193         return converter;
 194     }
 195 
 196 
 197     @Override
 198     public boolean equals(Object other) {
 199         if (other == this) return true;
 200         if (other == null || !(other instanceof EnumConverter)) return false;
 201         return (enumClass.equals(((EnumConverter)other).enumClass));
 202     }
 203 
 204     @Override
 205     public int hashCode() {
 206         return enumClass.hashCode();
 207     }
 208 
 209     @Override
 210     public String toString() {
 211         return "EnumConveter[" + enumClass.getName() + "]";
 212     }
 213 }