1 package org.apache.fulcrum.intake.model;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.io.Serializable;
23 import java.util.ArrayList;
24 import java.util.HashMap;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.ListIterator;
28 import java.util.Map;
29
30 import javax.xml.bind.Unmarshaller;
31 import javax.xml.bind.annotation.XmlAccessType;
32 import javax.xml.bind.annotation.XmlAccessorType;
33 import javax.xml.bind.annotation.XmlAttribute;
34 import javax.xml.bind.annotation.XmlElement;
35 import javax.xml.bind.annotation.XmlType;
36 import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
37
38 import org.apache.avalon.framework.logger.LogEnabled;
39 import org.apache.avalon.framework.logger.Logger;
40 import org.apache.commons.lang3.StringUtils;
41 import org.apache.commons.pool2.BaseKeyedPooledObjectFactory;
42 import org.apache.commons.pool2.PooledObject;
43 import org.apache.commons.pool2.impl.DefaultPooledObject;
44 import org.apache.fulcrum.intake.IntakeException;
45 import org.apache.fulcrum.intake.IntakeServiceFacade;
46 import org.apache.fulcrum.intake.Retrievable;
47 import org.apache.fulcrum.parser.ValueParser;
48
49
50
51
52
53
54
55
56
57 @XmlType(name="group")
58 @XmlAccessorType(XmlAccessType.NONE)
59 public class Group implements Serializable, LogEnabled
60 {
61
62 private static final long serialVersionUID = -5452725641409669284L;
63
64 public static final String EMPTY = "";
65
66
67
68
69 public static final String NEW = "_0";
70
71
72 private transient Logger log;
73
74
75
76
77
78 @XmlAttribute(name="key", required=true)
79 private String gid;
80
81
82
83
84 @XmlAttribute(required=true)
85 private String name;
86
87
88
89
90 @XmlAttribute
91 private int poolCapacity = 128;
92
93
94
95
96 @XmlAttribute(name="mapToObject")
97 private String defaultMapToObject;
98
99
100
101
102 private AppData parent;
103
104
105
106
107 private Map<String, Field<?>> fieldsByName;
108
109
110
111
112 private Map<String, Field<?>[]> mapToObjectFields;
113
114
115
116
117 private LinkedList<Field<?>> fields;
118
119
120
121
122
123 private String oid;
124
125
126
127
128 private transient ValueParser pp;
129
130
131
132
133 private boolean isDeclared;
134
135
136
137
138 public Group()
139 {
140 super();
141 this.fields = new LinkedList<Field<?>>();
142 }
143
144
145
146
147 @Override
148 public void enableLogging(Logger logger)
149 {
150 this.log = logger.getChildLogger(getClass().getSimpleName());
151 }
152
153
154
155
156
157
158
159
160 public Group init(ValueParser pp) throws IntakeException
161 {
162 return init(NEW, pp);
163 }
164
165
166
167
168
169
170
171
172
173
174 public Group init(String key, ValueParser pp) throws IntakeException
175 {
176 this.oid = key;
177 this.pp = pp;
178 for (ListIterator<Field<?>> i = fields.listIterator(fields.size()); i.hasPrevious();)
179 {
180 i.previous().init(pp);
181 }
182 for (ListIterator<Field<?>> i = fields.listIterator(fields.size()); i.hasPrevious();)
183 {
184 Field<?> field = i.previous();
185 if (field.isSet() && !field.isValidated())
186 {
187 field.validate();
188 }
189 }
190 return this;
191 }
192
193
194
195
196
197
198
199 public Group init(Retrievable obj)
200 {
201 this.oid = obj.getQueryKey();
202
203 Class<?> cls = obj.getClass();
204 while (cls != null)
205 {
206 Field<?>[] flds = mapToObjectFields.get(cls.getName());
207 if (flds != null)
208 {
209 for (int i = flds.length - 1; i >= 0; i--)
210 {
211 flds[i].init(obj);
212 }
213 }
214
215
216 Class<?>[] interfaces = cls.getInterfaces();
217 for (int idx = 0; idx < interfaces.length; idx++)
218 {
219 Field<?>[] interfaceFields =
220 mapToObjectFields.get(interfaces[idx].getName());
221 if (interfaceFields != null)
222 {
223 for (int i = 0; i < interfaceFields.length; i++)
224 {
225 interfaceFields[i].init(obj);
226 }
227 }
228 }
229
230 cls = cls.getSuperclass();
231 }
232
233 return this;
234 }
235
236
237
238
239
240
241 public String[] getFieldNames()
242 {
243 String nameList[] = new String[fields.size()];
244 int i = 0;
245 for (Field<?> f : fields)
246 {
247 nameList[i++] = f.getName();
248 }
249 return nameList;
250 }
251
252
253
254
255
256
257
258 public String getIntakeGroupName()
259 {
260 return name;
261 }
262
263
264
265
266
267
268 public int getPoolCapacity()
269 {
270 return poolCapacity;
271 }
272
273
274
275
276
277
278
279 public String getGID()
280 {
281 return gid;
282 }
283
284
285
286
287
288
289
290 public String getOID()
291 {
292 return oid;
293 }
294
295
296
297
298
299
300 public String getObjectKey()
301 {
302 return gid + oid;
303 }
304
305
306
307
308
309
310 public String getDefaultMapToObject()
311 {
312 return defaultMapToObject;
313 }
314
315
316
317
318
319
320
321
322 public List<Group> getObjects(ValueParser pp) throws IntakeException
323 {
324 ArrayList<Group> objs = null;
325 String[] oids = pp.getStrings(gid);
326 if (oids != null)
327 {
328 objs = new ArrayList<Group>(oids.length);
329 for (int i = oids.length - 1; i >= 0; i--)
330 {
331 objs.add(IntakeServiceFacade.getGroup(name).init(oids[i], pp));
332 }
333 }
334 return objs;
335 }
336
337
338
339
340
341
342
343
344 public Field<?> get(String fieldName)
345 throws IntakeException
346 {
347 if (fieldsByName.containsKey(fieldName))
348 {
349 return fieldsByName.get(fieldName);
350 }
351 else
352 {
353 throw new IntakeException("Intake Field name: " + fieldName +
354 " not found in Group " + name);
355 }
356 }
357
358
359
360
361
362 public List<Field<?>> getFields()
363 {
364 return fields;
365 }
366
367
368
369
370
371
372 @XmlElement(name="field")
373 @XmlJavaTypeAdapter(FieldAdapter.class)
374 protected void setFields(List<Field<?>> inputFields)
375 {
376 fields = new LinkedList<Field<?>>(inputFields);
377 }
378
379
380
381
382
383
384 public boolean isAllValid()
385 {
386 boolean valid = true;
387 for (ListIterator<Field<?>> i = fields.listIterator(fields.size()); i.hasPrevious();)
388 {
389 Field<?> field = i.previous();
390 valid &= field.isValid();
391 if (log.isDebugEnabled() && !field.isValid())
392 {
393 log.debug("Group(" + oid + "): " + name + "; Field: "
394 + field.getName() + "; value=" +
395 field.getValue() + " is invalid!");
396 }
397 }
398 return valid;
399 }
400
401
402
403
404
405
406
407
408 public void setProperties(Object obj) throws IntakeException
409 {
410 Class<?> cls = obj.getClass();
411
412 while (cls != null)
413 {
414 if (log.isDebugEnabled())
415 {
416 log.debug("setProperties(" + cls.getName() + ")");
417 }
418
419 Field<?>[] flds = mapToObjectFields.get(cls.getName());
420 if (flds != null)
421 {
422 for (int i = flds.length - 1; i >= 0; i--)
423 {
424 flds[i].setProperty(obj);
425 }
426 }
427
428
429 Class<?>[] interfaces = cls.getInterfaces();
430 for (int idx = 0; idx < interfaces.length; idx++)
431 {
432 Field<?>[] interfaceFields =
433 mapToObjectFields.get(interfaces[idx].getName());
434 if (interfaceFields != null)
435 {
436 for (int i = 0; i < interfaceFields.length; i++)
437 {
438 interfaceFields[i].setProperty(obj);
439 }
440 }
441 }
442
443 cls = cls.getSuperclass();
444 }
445
446 log.debug("setProperties() finished");
447 }
448
449
450
451
452
453
454
455
456
457
458 public void setValidProperties(Object obj)
459 {
460 Class<?> cls = obj.getClass();
461 while (cls != null)
462 {
463 Field<?>[] flds = mapToObjectFields.get(cls.getName());
464 if (flds != null)
465 {
466 for (int i = flds.length - 1; i >= 0; i--)
467 {
468 try
469 {
470 flds[i].setProperty(obj);
471 }
472 catch (IntakeException e)
473 {
474
475 }
476 }
477 }
478
479
480 Class<?>[] interfaces = cls.getInterfaces();
481 for (int idx = 0; idx < interfaces.length; idx++)
482 {
483 Field<?>[] interfaceFields =
484 mapToObjectFields.get(interfaces[idx].getName());
485 if (interfaceFields != null)
486 {
487 for (int i = 0; i < interfaceFields.length; i++)
488 {
489 try
490 {
491 interfaceFields[i].setProperty(obj);
492 }
493 catch(IntakeException e)
494 {
495
496 }
497 }
498 }
499 }
500
501 cls = cls.getSuperclass();
502 }
503 }
504
505
506
507
508
509
510
511
512
513
514
515 public void getProperties(Object obj) throws IntakeException
516 {
517 Class<?> cls = obj.getClass();
518
519 while (cls != null)
520 {
521 Field<?>[] flds = mapToObjectFields.get(cls.getName());
522 if (flds != null)
523 {
524 for (int i = flds.length - 1; i >= 0; i--)
525 {
526 flds[i].getProperty(obj);
527 }
528 }
529
530
531 Class<?>[] interfaces = cls.getInterfaces();
532 for (int idx = 0; idx < interfaces.length; idx++)
533 {
534 Field<?>[] interfaceFields =
535 mapToObjectFields.get(interfaces[idx].getName());
536 if (interfaceFields != null)
537 {
538 for (int i = 0; i < interfaceFields.length; i++)
539 {
540 interfaceFields[i].getProperty(obj);
541 }
542 }
543 }
544
545 cls = cls.getSuperclass();
546 }
547 }
548
549
550
551
552
553 public void removeFromRequest()
554 {
555 if (pp != null)
556 {
557 String[] groups = pp.getStrings(gid);
558 if (groups != null)
559 {
560 pp.remove(gid);
561 for (int i = 0; i < groups.length; i++)
562 {
563 if (groups[i] != null && !groups[i].equals(oid))
564 {
565 pp.add(gid, groups[i]);
566 }
567 }
568 for (ListIterator<Field<?>> i = fields.listIterator(fields.size()); i.hasPrevious();)
569 {
570 i.previous().removeFromRequest();
571 }
572 }
573 }
574 }
575
576
577
578
579
580 public void resetDeclared()
581 {
582 isDeclared = false;
583 }
584
585
586
587
588
589
590
591 public String getHtmlFormInput()
592 {
593 StringBuilder sb = new StringBuilder(64);
594 appendHtmlFormInput(sb);
595 return sb.toString();
596 }
597
598
599
600
601
602
603
604 public void appendHtmlFormInput(StringBuilder sb)
605 {
606 if (!isDeclared)
607 {
608 isDeclared = true;
609 sb.append("<input type=\"hidden\" name=\"")
610 .append(gid)
611 .append("\" value=\"")
612 .append(oid)
613 .append("\"/>\n");
614 }
615 }
616
617
618
619
620
621 @Override
622 public String toString()
623 {
624 StringBuilder result = new StringBuilder();
625
626 result.append("<group name=\"").append(getIntakeGroupName()).append("\"");
627 result.append(" key=\"").append(getGID()).append("\"");
628 result.append(">\n");
629
630 if (fields != null)
631 {
632 for (Field<?> field : fields)
633 {
634 result.append(field);
635 }
636 }
637
638 result.append("</group>\n");
639
640 return result.toString();
641 }
642
643
644
645
646
647
648 public AppData getAppData()
649 {
650 return parent;
651 }
652
653
654
655
656
657
658
659 public void afterUnmarshal(Unmarshaller um, Object parent)
660 {
661 this.parent = (AppData)parent;
662
663
664 fieldsByName = new HashMap<String, Field<?>>((int) (1.25 * fields.size() + 1));
665
666 for (Field<?> field : fields)
667 {
668 fieldsByName.put(field.getName(), field);
669 }
670
671 Map<String, List<Field<?>>> mapToObjectFieldLists =
672 new HashMap<String, List<Field<?>>>((int) (1.25 * fields.size() + 1));
673
674
675 for (Field<?> field : fields)
676 {
677 if (StringUtils.isNotEmpty(field.mapToObject))
678 {
679 field.mapToObject = this.parent.getBasePackage() + field.mapToObject;
680 }
681
682
683 List<Field<?>> tmpFields = mapToObjectFieldLists.get(field.getMapToObject());
684 if (tmpFields == null)
685 {
686 tmpFields = new ArrayList<Field<?>>(fields.size());
687 mapToObjectFieldLists.put(field.getMapToObject(), tmpFields);
688 }
689
690 tmpFields.add(field);
691 }
692
693
694 mapToObjectFields = new HashMap<String, Field<?>[]>((int) (1.25 * fields.size() + 1));
695
696 for (Map.Entry<String, List<Field<?>>> entry : mapToObjectFieldLists.entrySet())
697 {
698 mapToObjectFields.put(entry.getKey(),
699 entry.getValue().toArray(new Field[entry.getValue().size()]));
700 }
701 }
702
703
704
705 public static class GroupFactory
706 extends BaseKeyedPooledObjectFactory<String, Group>
707 {
708 private final AppData appData;
709
710 public GroupFactory(AppData appData)
711 {
712 this.appData = appData;
713 }
714
715
716
717
718
719
720
721 @Override
722 public Group create(String key) throws IntakeException
723 {
724 return appData.getGroup(key);
725 }
726
727
728
729
730 @Override
731 public PooledObject<Group> wrap(Group group)
732 {
733 return new DefaultPooledObject<Group>(group);
734 }
735
736
737
738
739
740
741 @Override
742 public void passivateObject(String key, PooledObject<Group> pooledGroup)
743 {
744 Group group = pooledGroup.getObject();
745 group.oid = null;
746 group.pp = null;
747 for (ListIterator<Field<?>> i = group.fields.listIterator(group.fields.size());
748 i.hasPrevious();)
749 {
750 i.previous().dispose();
751 }
752 group.isDeclared = false;
753 }
754 }
755 }
756
757