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