001 /*
002 * Copyright 2005,2009 Ivan SZKIBA
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.ini4j.tutorial;
017
018 import org.ini4j.Options;
019
020 import org.ini4j.sample.Dwarf;
021
022 import org.ini4j.test.DwarfsData;
023 import org.ini4j.test.Helper;
024
025 import static org.junit.Assert.*;
026
027 import java.io.File;
028 import java.io.FileReader;
029 import java.io.IOException;
030
031 import java.util.Set;
032
033 //<editor-fold defaultstate="collapsed" desc="apt documentation">
034 //|
035 //| ----------------
036 //| Options Tutorial
037 //|
038 //|Options Tutorial - java.util.Properties replacement
039 //|
040 //| Options (org.ini4j.Options) is a java.util.Properties replacement with
041 //| several useful features, like:
042 //|
043 //| * variable/macro substitution. You may refer to other property's value with
044 //| $\{NAME\} expression, where NAME is the name of the referred property.
045 //| ofcourse you can use more than one property reference per property, and
046 //| you can mix constant text and property references:
047 //|
048 //|+-------------------+
049 //|player.name = Joe
050 //|player.greetings = Hi ${player.name}!
051 //|player.domain = foo.bar
052 //|player.email = ${player.name}@${player.domain}
053 //|+-------------------+
054 //|
055 //| * multiply property values. You can refer to multi value properties with
056 //| integer indexes. Ofcource it is also works in macro/variable substitutions:
057 //| $\{user.fortuneNumber\[2\]\}
058 //|
059 //|+-------------------+
060 //|player.fortuneNumber = 33
061 //|player.fortuneNumber = 44
062 //|player.fortuneNumber = 55
063 //|player.fortuneNumber = 66
064 //|
065 //|magicNumber = ${player.foruneNumber[1]}
066 //|+--------------------+
067 //|
068 //| The magicNumber property will have value: <<<44>>>
069 //|
070 //| * as Java class, Options is basicly map of Strings indexed with Strings. It
071 //| is standard Collection API (ok, it is a bit enhanced to deal with multi
072 //| values, but in general it is a Map\<String,String\>).
073 //|
074 //| * Java Beans api. You can read/write properties in type safe way. To do it
075 //| you just define an interface, call Options#as() method. This method will
076 //| provide an implementation of given interface on top of Options. Property
077 //| types are mapped automatically between Java type and String.
078 //|
079 //|* Why need Options
080 //|
081 //| With standard Properties class there is several small problem. Most of them
082 //| came from backward compatibility.
083 //|
084 //| * not implements Map\<String,String\>, but Map\<Object,Object\>. If you
085 //| want to use Collections api, it is a bit unconfortable.
086 //|
087 //| * only single property values allowed. Probably you already see ugly
088 //| workarounds: index number in property names, like: file.1, file.2 ...
089 //|
090 //| * no macro/variable substitution. In some environment, like
091 //| Apache Ant, you can use ${name} like references, but with standard
092 //| java.util.Properties you can't.
093 //|
094 //| As side effect of \[ini4j\] development, there is a solution for aboves.
095 //| This is the org.ini4j.Options class, which is basicly a feature rich
096 //| replacement for java.util.Properties.
097 //|
098 //| Code sniplets in this tutorial tested with the following .opt file:
099 //| {{{../sample/dwarfs.opt.html}dwarfs.opt}}
100 //|
101 //</editor-fold>
102 public class OptTutorial extends AbstractTutorial
103 {
104 public static final String FILENAME = "../sample/dwarfs.opt";
105
106 public static void main(String[] args) throws Exception
107 {
108 new OptTutorial().run(filearg(args));
109 }
110
111 protected void run(File arg) throws Exception
112 {
113 Options opt = new Options(arg.toURI().toURL());
114
115 sample01(arg);
116 sample02(opt);
117 }
118
119 //|
120 //|* Instantiating
121 //|
122 //| There is nothing special with instantiating Options object, but there is a
123 //| few constructor, to simplify loading data. These constructors simply call
124 //| the <<<load()>>> method on newly created instance. Ofcource these
125 //| constructors are throws IOException.
126 //{
127 void sample01(File file) throws IOException
128 {
129 Options opt = new Options();
130
131 //
132 // or instantiate and load data:
133 //
134 opt = new Options(new FileReader(file));
135
136 //}
137 assertFalse(opt.keySet().isEmpty());
138 }
139
140 //|
141 //|* Map of String
142 //{
143 void sample02(Options opt)
144 {
145 Set<String> optionNames = opt.keySet();
146
147 //
148 String age = opt.get("age");
149 String weight = opt.fetch("weight");
150 String height = opt.fetch("height");
151
152 //}
153 //|
154 //| The Options is a MultiMap\<String,String\>, that is, a map that assigns
155 //| String values to String keys. So the <<<get>>> method is used to get values
156 //| inside the options. To get a value, besides <<<get()>>> you can also
157 //| use <<<fetch()>>> which resolves any occurrent $\{option\} format
158 //| variable references in the needed value.
159 Helper.assertEquals(DwarfsData.dopey, opt.as(Dwarf.class));
160 }
161 }