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 */
016package org.ini4j.tutorial;
017
018import org.ini4j.Config;
019import org.ini4j.Ini;
020import org.ini4j.Options;
021
022import org.ini4j.sample.Dwarf;
023import org.ini4j.sample.DwarfBean;
024import org.ini4j.sample.Dwarfs;
025
026import org.ini4j.test.DwarfsData;
027
028import static org.junit.Assert.*;
029
030import java.io.File;
031import java.io.IOException;
032
033import java.net.URI;
034import java.net.URL;
035
036//<editor-fold defaultstate="collapsed" desc="apt documentation">
037//|
038//|                -------------
039//|                Bean Tutorial
040//|
041//|Bean Tutorial - Using your own API !
042//|
043//| Yes, it can be done! To access the contents of sections you can use any of
044//| your self-defined Java Beans compatible API.
045//| In order to do this you only have to create a Java Beans-style interface or class.
046//|
047//| Source code for beans: {{{../sample/Dwarf.java.html}Dwarf}},
048//| {{{../sample/DwarfBean.java.html}DwarfBean}}
049//|
050//| Code sniplets in this tutorial tested with the following .ini file:
051//| {{{../sample/dwarfs.ini.html}dwarfs.ini}}
052//|
053//</editor-fold>
054public class BeanTutorial extends AbstractTutorial
055{
056    public static void main(String[] args) throws Exception
057    {
058        new BeanTutorial().run(filearg(args));
059    }
060
061    @Override protected void run(File arg) throws Exception
062    {
063        Ini ini = new Ini(arg.toURI().toURL());
064
065        sample01(ini);
066        sample02(ini);
067        sample03(ini);
068        sample04(arg.toURI().toURL());
069        Options opts = new Options();
070
071        opts.putAll(ini.get(Dwarfs.PROP_BASHFUL));
072        sample05(opts);
073
074        //
075        File optFile = new File(arg.getParentFile(), OptTutorial.FILENAME);
076
077        sample06(optFile.toURI().toURL());
078    }
079
080//|
081//|* Accessing sections as beans
082//|
083//| While writing a program we usually know the type of the section's values,
084//| so we can define one or more java interfaces to access them. An advantage of
085//| this solution is that the programmer doesn't have to convert the values
086//| because they are converted automatically to the type defined in the
087//| interface.
088//|
089//| Ofcourse you may use setters as well, not just getters. In this way you can
090//| change values type safe way.
091//{
092    void sample01(Ini ini)
093    {
094        Ini.Section sec = ini.get("happy");
095        Dwarf happy = sec.as(Dwarf.class);
096        int age = happy.getAge();
097        URI homePage = happy.getHomePage();
098
099        happy.setWeight(45.55);
100
101//}
102//|
103//| The <<<happy instanceof Dwarf>>> relation is of course fulfilled in the
104//| example above.
105//|
106        assertEquals(DwarfsData.happy.homePage.toString(), homePage.toString());
107        assertEquals(DwarfsData.happy.age, age);
108        assertEquals(45.55, happy.getWeight(), 0.01);
109    }
110
111//|
112//|* Marshalling beans
113//|
114//| Sometimes we want to store existing java beans in text file. This operation
115//| usually called marshalling.
116//|
117//| With [ini4j] it is easy to store bean properties in a section. You simply
118//| create a section, and call the sections's <<<from()>>> method. Thats it.
119//{
120    void sample02(Ini ini)
121    {
122        DwarfBean sleepy = new DwarfBean();
123
124        sleepy.setAge(87);
125        sleepy.setWeight(44.3);
126        Ini.Section sec = ini.add("sleepy");
127
128        sec.from(sleepy);
129
130//}
131//|
132        assertTrue(sec.containsKey(Dwarf.PROP_AGE));
133        assertTrue(sec.containsKey(Dwarf.PROP_WEIGHT));
134    }
135
136//|
137//|* Unmarshalling beans
138//|
139//| If you have a marshalled bean in text file then you may want to read it
140//| into bean. This operation usually called unmarshalling.
141//|
142//| With [ini4j] it is easy to load bean properties from a section. You simply
143//| instantiate a bean, and call the sections's <<<to()>>> method. Thats it.
144//{
145    void sample03(Ini ini)
146    {
147        DwarfBean grumpy = new DwarfBean();
148
149        ini.get("grumpy").to(grumpy);
150
151//}
152//|
153        assertEquals(DwarfsData.grumpy.age, grumpy.getAge());
154        assertEquals(DwarfsData.grumpy.homeDir, grumpy.getHomeDir());
155    }
156
157//|
158//|* Indexed properties
159//|
160//| For handling indexed properties, you should allow mulpti option value
161//| handling in configuration. After enabling this feature, option may contains
162//| multiply values (multi line in file). These values can mapped to indexed
163//| bean property.
164//{
165    void sample04(URL location) throws IOException
166    {
167        Config cfg = new Config();
168
169        cfg.setMultiOption(true);
170        Ini ini = new Ini();
171
172        ini.setConfig(cfg);
173        ini.load(location);
174        Ini.Section sec = ini.get("sneezy");
175        Dwarf sneezy = sec.as(Dwarf.class);
176        int[] numbers = sneezy.getFortuneNumber();
177
178        //
179        // same as above but with unmarshalling...
180        //
181        DwarfBean sneezyBean = new DwarfBean();
182
183        sec.to(sneezyBean);
184        numbers = sneezyBean.getFortuneNumber();
185
186//}
187        assertArrayEquals(DwarfsData.sneezy.fortuneNumber, numbers);
188        assertEquals(DwarfsData.sneezy.fortuneNumber.length, sec.length("fortuneNumber"));
189        assertArrayEquals(DwarfsData.sneezy.fortuneNumber, sneezy.getFortuneNumber());
190        assertArrayEquals(DwarfsData.sneezy.fortuneNumber, sneezyBean.getFortuneNumber());
191    }
192
193//|
194//|* Options
195//|
196//| Not only Ini and Ini.Section has bean interface. There is a bean interface
197//| for OptionMap class and each derived class for example for Options.
198//| Options is an improved java.util.Properties replacement.
199//{
200    void sample05(Options opts)
201    {
202        Dwarf dwarf = opts.as(Dwarf.class);
203        int age = dwarf.getAge();
204
205        //
206        // same as above but with unmarshalling
207        //
208        DwarfBean dwarfBean = new DwarfBean();
209
210        opts.to(dwarfBean);
211        age = dwarfBean.getAge();
212
213//}
214//|
215//| In sample above the top level properties (like "age") mapped to bean
216//| properties.
217//|
218        assertEquals(DwarfsData.bashful.age, dwarf.getAge());
219        assertEquals(DwarfsData.bashful.age, dwarfBean.getAge());
220    }
221
222//|
223//|* Prefixed mapping
224//|
225//| Both Ini.Section and Options has possibility to add a prefix to property
226//| names while mapping from bean property name to Ini.Section or Options
227//| key.
228//{
229    void sample06(URL optPath) throws IOException
230    {
231        Options opt = new Options(optPath);
232        Dwarf dwarf = opt.as(Dwarf.class, "happy.");
233        DwarfBean bean = new DwarfBean();
234
235        opt.to(bean, "dopey.");
236
237//}
238//|
239//| In the above example, <<<dwarf>>> bean will contain properties starts with
240//| <<<happy.>>> while <<<bean>>> will contain properties starts with
241//| <<<dopey.>>>
242        assertEquals(DwarfsData.happy.age, dwarf.getAge());
243        assertEquals(DwarfsData.dopey.age, bean.getAge());
244    }
245//}
246}