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.Config;
019    import org.ini4j.Ini;
020    import org.ini4j.Options;
021    
022    import org.ini4j.sample.Dwarf;
023    import org.ini4j.sample.DwarfBean;
024    import org.ini4j.sample.Dwarfs;
025    
026    import org.ini4j.test.DwarfsData;
027    
028    import static org.junit.Assert.*;
029    
030    import java.io.File;
031    import java.io.IOException;
032    
033    import java.net.URI;
034    import 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>
054    public 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    }