001package org.biopax.paxtools.impl;
002
003import org.biopax.paxtools.controller.*;
004import org.biopax.paxtools.model.BioPAXElement;
005import org.biopax.paxtools.model.BioPAXFactory;
006import org.biopax.paxtools.model.BioPAXLevel;
007import org.biopax.paxtools.model.Model;
008import org.biopax.paxtools.util.IllegalBioPAXArgumentException;
009
010import java.lang.reflect.Array;
011import java.lang.reflect.Field;
012import java.util.*;
013
014/**
015 * This factory returns decorated objects for testing.
016 */
017public class MockFactory extends BioPAXFactory
018{
019// ------------------------------ FIELDS ------------------------------
020
021
022        private static final List<String> strings = Arrays.asList(" ", "alpha", "beta", "gamma");
023
024        private static final List<Float> floats = Arrays.asList(Float.MAX_VALUE, 1.0F, 0.0F, Float.MIN_VALUE);
025
026        private static final List<Double> doubles = Arrays.asList(Double.MAX_VALUE, 1.0, 0.0, Double.MIN_VALUE);
027
028        private static final List<Integer> ints = Arrays.asList(Integer.MAX_VALUE, 1, 0, Integer.MIN_VALUE + 1);
029
030        private static final List<Boolean> booleans = Arrays.asList(Boolean.TRUE, Boolean.FALSE);
031
032        private static final String base = "mock://id/";
033
034        private int id = 0;
035
036
037        private EditorMap map;
038
039        private BioPAXLevel level;
040
041// --------------------------- CONSTRUCTORS ---------------------------
042
043        public MockFactory(BioPAXLevel level)
044        {
045                this.level = level;
046                this.map = SimpleEditorMap.get(level);
047        }
048
049        @Override
050        public <T extends BioPAXElement> T create(Class<T> aClass, String uri)
051        {
052                T t = this.getLevel().getDefaultFactory().create(aClass, uri);
053                populateMock(t);
054                return t;
055        }
056
057        @Override
058        public BioPAXElement create(String localName, String uri)
059        {
060                BioPAXElement bpe = this.getLevel().getDefaultFactory().create(localName, uri);
061                populateMock(bpe);
062                return bpe;
063        }
064
065        private void populateMock(BioPAXElement bpe)
066        {
067                Set<PropertyEditor> propertyEditors = map.getEditorsOf(bpe);
068
069                for (PropertyEditor propertyEditor : propertyEditors)
070                {
071                        boolean multiple = propertyEditor.isMultipleCardinality();
072                        Object value = null;
073                        if (propertyEditor instanceof StringPropertyEditor)
074                        {
075                                value = getStrings(bpe, multiple);
076                        } else
077                        {
078                                Class range = propertyEditor.getRange();
079                                if (propertyEditor instanceof PrimitivePropertyEditor)
080                                {
081                                        if (range == float.class)
082                                        {
083                                                value = multiple ? floats : floats.get(1);
084                                        } else if (range == double.class)
085                                        {
086                                                value = multiple ? doubles : doubles.get(1);
087                                        } else if (range == int.class)
088                                        {
089                                                value = multiple ? ints : ints.get(1);
090                                        } else if (range == Boolean.class)
091                                        {
092                                                value = multiple ? booleans : booleans.get(1);
093                                        }
094                                } else if (propertyEditor instanceof EnumeratedPropertyEditor)
095                                {
096                                        Field[] fields = range.getFields();
097                                        if (multiple)
098                                        {
099                                                value = new HashSet();
100                                        }
101                                        for (Field field : fields)
102                                        {
103                                                if (field.isEnumConstant())
104                                                {
105                                                        try
106                                                        {
107                                                                if (multiple)
108                                                                {
109                                                                        ((Set) value).add(field.get(bpe));
110                                                                } else
111                                                                {
112                                                                        value = field.get(bpe);
113                                                                        break;
114                                                                }
115                                                        }
116                                                        catch (IllegalAccessException e)
117                                                        {
118                                                                throw new IllegalBioPAXArgumentException();
119                                                        }
120                                                }
121                                        }
122                                } else
123                                {
124//                                      if (!Entity.class.isAssignableFrom(range))
125//                                      {
126//                                              if (multiple)
127//                                              {
128//                                                      value = createRestrictedMock((ObjectPropertyEditor) propertyEditor, bpe, 3);
129//                                              } else
130//                                              {
131//                                                      value = createRestrictedMock((ObjectPropertyEditor) propertyEditor, bpe,
132//                                                                                   1).iterator().next();
133//                                              }
134//                                      }
135                                }
136                        }
137                        if (value != null)
138                        {
139                                if (multiple)
140                                {
141                                        Collection values = ((Collection) value);
142                                        if (!values.isEmpty())
143                                        {
144                                                Integer max = propertyEditor.getMaxCardinality(bpe.getModelInterface());
145                                                values = upToMax(values, max);
146
147                                                for (Object o : values)
148                                                {
149                                                        propertyEditor.setValueToBean(o, bpe);
150                                                }
151                                        } else
152                                        {
153                                                propertyEditor.setValueToBean(value, bpe);
154                                        }
155                                }
156                        }
157                }
158        }
159
160        private Object getStrings(BioPAXElement bpe, boolean multiple)
161        {
162                if (multiple)
163                {
164                        ArrayList<String> list = new ArrayList<String>(4);
165                        for (String str : strings)
166                        {
167                                list.add(bpe.getRDFId() + str);
168                        }
169                        return list;
170                } else return bpe.getRDFId() + strings.get(3);
171        }
172
173        private HashSet<BioPAXElement> createRestrictedMock(ObjectPropertyEditor propertyEditor, BioPAXElement bpe, int k)
174        {
175                HashSet<BioPAXElement> hashSet = new HashSet<BioPAXElement>();
176
177
178                Set<Class<? extends BioPAXElement>> rRanges = propertyEditor.getRestrictedRangesFor(bpe.getModelInterface());
179                for (Class<? extends BioPAXElement> rRange : rRanges)
180                {
181                        hashSet.add(createMock(rRange, bpe.getModelInterface()));
182                }
183                return hashSet;
184        }
185
186        private BioPAXElement createMock(Class<? extends BioPAXElement> toCreate, Class domain)
187        {
188                assert domain != null;
189                Class<? extends BioPAXElement> actual;
190                actual = findConcreteMockClass(toCreate, domain);
191                if (actual != null)
192                {
193                        return map.getLevel().getDefaultFactory().create(actual, base + id++);
194                } else return null;
195
196        }
197
198        private Class<? extends BioPAXElement> findConcreteMockClass(Class<? extends BioPAXElement> toCreate, Class domain)
199        {
200                Class<? extends BioPAXElement> actual = null;
201                if (map.getLevel().getDefaultFactory().canInstantiate(toCreate) && !toCreate.isAssignableFrom(domain))
202                {
203                        actual = toCreate;
204                } else
205                {
206                        Set<? extends Class<? extends BioPAXElement>> knownSubClassesOf = map.getKnownSubClassesOf(toCreate);
207                        for (Class<? extends BioPAXElement> subclass : knownSubClassesOf)
208                        {
209                                if (!subclass.isAssignableFrom(domain) && subclass != toCreate &&
210                                    subclass.getPackage().getName().startsWith("org.biopax.paxtools.model"))
211                                {
212                                        actual = findConcreteMockClass(subclass, domain);
213                                        break;
214                                }
215                        }
216                }
217                return actual;
218        }
219
220        private Collection upToMax(Collection values, Integer max)
221        {
222                int size = values.size();
223                if (max != null && max < size)
224                {
225                        values = new ArrayList(values);
226                        for (int i = size - 1; i == max; i--)
227                        {
228                                ((List) values).remove(i);
229                        }
230                        assert values.size() == max;
231                }
232                return values;
233        }
234
235
236        public BioPAXLevel getLevel()
237        {
238                return this.level;
239        }
240
241        @Override
242        public String mapClassName(Class<? extends BioPAXElement> aClass) {
243                return this.getLevel().getDefaultFactory().mapClassName(aClass);
244        }
245        
246        
247        public <T extends BioPAXElement> T[] create(Model model, Class<T> biopaxClass, int number, String pre)
248        {
249                T[] result = (T[]) Array.newInstance(biopaxClass, number);
250
251                for (int i = 0; i < number; i++)
252                {
253                        result[i] = model.addNew(biopaxClass, biopaxClass.getSimpleName() + pre + i);
254                }
255                return result;
256        }
257
258        public <T extends BioPAXElement> T[] create(Model model, Class<T> biopaxClass, int number)
259        {
260                return this.create(model,biopaxClass, number, "");
261        }
262
263        public void bindInPairs(ObjectPropertyEditor editor, BioPAXElement... pairs)
264        {
265                for (int i = 0; i < pairs.length; i++)
266                {
267                        BioPAXElement bean = pairs[i++];
268                        BioPAXElement value = pairs[i];
269                        editor.setValueToBean(value, bean);
270                }
271        }
272
273        public void bindArrays(ObjectPropertyEditor editor, BioPAXElement[] beans, BioPAXElement[] values)
274        {
275                for (int i = 0; i < beans.length; i++)
276                {
277                        BioPAXElement bean = beans[i];
278                        BioPAXElement value = values[i];
279                        editor.setValueToBean(value, bean);
280                }
281        }
282
283        public void bindInPairs(String editor, BioPAXElement... pairs)
284        {
285                this.bindInPairs(this.editor(editor, pairs[0].getModelInterface()),pairs);
286        }
287
288        public void bindArrays(String editor, BioPAXElement[] beans, BioPAXElement[] values)
289        {
290                this.bindArrays(this.editor(editor, (Class<? extends BioPAXElement>) beans.getClass().getComponentType()),
291                                beans, values);
292        }
293
294        public ObjectPropertyEditor editor(String property, Class<? extends BioPAXElement> clazz)
295        {
296                return (ObjectPropertyEditor) map.getEditorForProperty(property, clazz);
297        }
298
299}