001    /*
002     * Copyright 2007-2008 The Kuali Foundation
003     *
004     * Licensed under the Educational Community 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.opensource.org/licenses/ecl2.php
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.kuali.rice.kew.xml;
017    
018    import java.io.IOException;
019    import java.io.InputStream;
020    import java.util.ArrayList;
021    import java.util.List;
022    
023    import javax.xml.bind.JAXBContext;
024    import javax.xml.bind.Unmarshaller;
025    import javax.xml.bind.UnmarshallerHandler;
026    import javax.xml.bind.util.ValidationEventCollector;
027    import javax.xml.parsers.SAXParserFactory;
028    import javax.xml.validation.Schema;
029    
030    import org.apache.commons.lang.StringUtils;
031    import org.apache.log4j.Logger;
032    import org.kuali.rice.core.xml.CoreNamespaceConstants;
033    import org.kuali.rice.core.xml.dto.DataXmlDto;
034    import org.kuali.rice.core.xml.schema.RiceSchemaValidationEventCollector;
035    import org.kuali.rice.core.xml.schema.RiceXmlSchemaFactory;
036    import org.xml.sax.Attributes;
037    import org.xml.sax.InputSource;
038    import org.xml.sax.SAXException;
039    import org.xml.sax.XMLFilter;
040    import org.xml.sax.helpers.XMLFilterImpl;
041    
042    
043    /**
044     * Parses groups from XML using JAXB.
045     *
046     * @see KimGroups
047     *
048     * @author Kuali Rice Team (rice.collab@kuali.org) 
049     *
050     */
051    public class GroupXmlJAXBParser implements XmlConstants {
052        private static final Logger LOG = Logger.getLogger(GroupXmlJAXBParser.class);
053        private static final String DEFAULT_GROUP_DESCRIPTION = "";
054        private static final String DEFAULT_GROUP_SCHEMA_NAME = "Groups-1.0.3.xsd";
055        
056            public DataXmlDto parse(InputStream in) throws IOException {
057            DataXmlDto groupsXmlDto = new DataXmlDto();
058                    JAXBContext jaxbContext;
059                    Unmarshaller unmarshaller;
060    
061                    try {
062                            jaxbContext = JAXBContext.newInstance(DataXmlDto.class);
063                            unmarshaller = jaxbContext.createUnmarshaller();
064                    }catch (Exception ex) {
065                            throw new RuntimeException("Error creating JAXB unmarshaller", ex);
066                    }
067    
068                    if (in == null) {
069                            LOG.warn("###############################");
070                            LOG.warn("#");
071                            LOG.warn("# XML Import input stream not found!");
072                            LOG.warn("#");
073                            LOG.warn("###############################");
074                    } else {
075                            try {
076    
077                                    groupsXmlDto = unmarshal(unmarshaller, in);
078    
079                            } catch (Exception ex) {
080                                    LOG.error(ex.getMessage());
081                                    throw new RuntimeException("Error parsing XML input stream", ex);
082                            }
083    
084                    }
085                    return groupsXmlDto;
086            }
087    
088            /**
089             * 
090             * This method returns a list of xmlfilters.  The order here matters. The fist element gets processed 
091             * first. FIFO.
092             * 
093             * @return
094             */
095            public List<XMLFilter> getXMLFilterList(){
096            
097                    List<XMLFilter> lRet = new ArrayList<XMLFilter>();
098                    
099                    lRet.add(new DataNamespaceURIFilter());         
100                    lRet.add(new GroupNamespaceURITransformationFilterPOC());
101                    lRet.add(new GroupNamespaceURIMemberTransformationFilterPOC());
102                    lRet.add(new GroupNamespaceURIFilter());
103                    
104                    return lRet;
105            }
106            
107            /**
108             * 
109             * This method takes in a list of xml filters and appends them together via
110             * parent child relationships.  The end result is one xml filter that can be applied to the parse.
111             * 
112             * @param filters
113             * @return
114             * @throws Exception
115             */
116            public XMLFilter getXMLFilter(List<XMLFilter> filters) throws Exception{
117                     SAXParserFactory spf = SAXParserFactory.newInstance();
118                 spf.setNamespaceAware(true);
119                 XMLFilter previous = null;
120                 XMLFilter current = null;
121                 
122                 for(int i=0; i< filters.size();i++)
123                 {           
124                     if(i==0){
125                             previous = filters.get(i);
126                             previous.setParent(spf.newSAXParser().getXMLReader());
127                     }else{
128                             current = filters.get(i);
129                             current.setParent(previous);
130                             previous = current;
131                     }
132                 }
133                 return current;
134            }
135            
136            protected DataXmlDto unmarshal(Unmarshaller unmarshaller, InputStream in) throws Exception {       
137    
138            UnmarshallerHandler handler = unmarshaller.getUnmarshallerHandler();
139            Schema groupSchema = RiceXmlSchemaFactory.getSchema(DEFAULT_GROUP_SCHEMA_NAME);
140            unmarshaller.setSchema(groupSchema);
141            ValidationEventCollector vec = new RiceSchemaValidationEventCollector();
142            unmarshaller.setEventHandler(vec);        
143            
144            XMLFilter filter = this.getXMLFilter(this.getXMLFilterList());
145            filter.setContentHandler(handler);
146           
147            filter.parse(new InputSource(in));
148            
149    
150            return (DataXmlDto)handler.getResult();
151       }
152            
153    //    protected GroupXmlDto unmarshalNew(Unmarshaller unmarshaller, InputStream in) throws Exception {
154    //        SAXParserFactory spf = SAXParserFactory.newInstance();
155    //        spf.setNamespaceAware(true);
156    //
157    //        XMLFilter filter = new TestGroupNamespaceURIFilter();
158    //        filter.setParent(spf.newSAXParser().getXMLReader());
159    //
160    //        unmarshaller.setListener(new Unmarshaller.Listener() {
161    //                      
162    //                      public void afterUnmarshal(Object target, Object parent) {
163    //                              GroupXmlDto gxd = (GroupXmlDto)target;
164    //                              //super.afterUnmarshal(target, parent);
165    //                      }
166    //              });
167    //        
168    //        
169    //        UnmarshallerHandler handler = unmarshaller.getUnmarshallerHandler();
170    //        filter.setContentHandler(handler);
171    //
172    //        filter.parse(new InputSource(in));
173    //
174    //        return (GroupXmlDto)handler.getResult();
175    //    }
176    //
177    //    protected GroupInfo generateGroupInfo(GroupXmlDto groupDto){
178    //      IdentityManagementService identityManagementService = KIMServiceLocator.getIdentityManagementService();
179    //      
180    //      List<String> errors = new ArrayList<String>();
181    //      GroupInfo gi = new GroupInfo();
182    //      List<KimTypeAttributeInfo> typeAttributes = null;
183    //      
184    //      if(isBlank(groupDto.getNamespaceCode())){
185    //              errors.add("Namespace must have a value.");
186    //      }else{
187    //              gi.setNamespaceCode(groupDto.getNamespaceCode());
188    //      }
189    //      
190    //      if(groupDto.getKimType() != null){
191    //              KimTypeInfo kimTypeInfo = null;
192    //              if(!isBlank(groupDto.getKimType().getKimTypeId())){
193    //                       kimTypeInfo = KIMServiceLocator.getTypeInfoService().getKimType(groupDto.getKimType().getKimTypeId());
194    //              }
195    //              if(!isBlank(groupDto.getKimType().getName()) && !isBlank(groupDto.getKimType().getNamespaceCode())){
196    //                      kimTypeInfo = KIMServiceLocator.getTypeInfoService().getKimTypeByName(groupDto.getKimType().getNamespaceCode(), groupDto.getKimType().getName());
197    //              }
198    //              
199    //              if (kimTypeInfo == null) {
200    //              errors.add("Invalid typeId or type name and namespace specified.");
201    //            } else  {
202    //              gi.setKimTypeId(kimTypeInfo.getKimTypeId());
203    //              typeAttributes = kimTypeInfo.getAttributeDefinitions();
204    //            }            
205    //      } else{
206    //              KimTypeInfo kimTypeDefault = KIMServiceLocator.getTypeInfoService().getKimTypeByName(KimConstants.KIM_TYPE_DEFAULT_NAMESPACE, KimConstants.KIM_TYPE_DEFAULT_NAME);
207    //            if (kimTypeDefault != null) {
208    //              gi.setKimTypeId(kimTypeDefault.getKimTypeId());
209    //              typeAttributes = kimTypeDefault.getAttributeDefinitions();
210    //            } else {
211    //              errors.add("Failed to locate the 'Default' group type!  Please ensure that it's in your database.");
212    //            }
213    //      }
214    //      
215    //      //Active Indicator
216    //        gi.setActive(groupDto.isActive());
217    //        
218    //      //Get list of attribute keys
219    //        List<String> validAttributeKeys = new ArrayList<String>();
220    //        for (KimTypeAttributeInfo attribute : typeAttributes) {
221    //            validAttributeKeys.add(attribute.getAttributeName());
222    //        }
223    //        //Group attributes
224    //        if (groupDto.getAttributes() != null) {
225    //              AttributeSet attributeSet = new AttributeSet();
226    //            for (String key : groupDto.getAttributes().keySet() ) {
227    //                String value = groupDto.getAttributes().get(key);
228    //                attributeSet.put(key, value);
229    //                if (!validAttributeKeys.contains(key)) {
230    //                    errors.add("Invalid attribute specified.");
231    //                }
232    //            }
233    //            if (attributeSet.size() > 0) {
234    //                gi.setAttributes(attributeSet);
235    //            }
236    //        }
237    //        
238    //        // Group Members
239    //        for(GroupMembershipXmlDto groupMember : groupDto.getMembers()){
240    //              
241    //              GroupMembershipInfo gmi = new GroupMembershipInfo(groupDto.getGroupId(), null, null, null, null, null);
242    //              if(!isBlank(groupMember.getMemberId())){
243    //                      KimPrincipal principal = identityManagementService.getPrincipal(groupMember.getMemberId());
244    //                      gmi.setMemberId(principal.getPrincipalId());
245    //                      gmi.setMemberTypeCode(KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
246    //              }
247    //              if(!isBlank(groupMember.getMemberName())){
248    //                      KimPrincipal principal = identityManagementService.getPrincipalByPrincipalName(groupMember.getMemberName());
249    //                      gmi.setMemberId(principal.getPrincipalId());
250    //                      gmi.setMemberTypeCode(KimGroupMemberTypes.PRINCIPAL_MEMBER_TYPE);
251    //              }
252    //              if(groupMember.getGroupName() != null){
253    //                      Group group = identityManagementService.getGroupByName(groupMember.getGroupName().getNamespaceCode(),groupMember.getGroupName().getName());
254    //                      gmi.setMemberId(group.getGroupId());
255    //                      gmi.setMemberTypeCode(KimGroupMemberTypes.GROUP_MEMBER_TYPE);
256    //              }
257    //              if(groupMember.getGroupName() != null){
258    //                      Group group = identityManagementService.getGroupByName(groupMember.getGroupName().getNamespaceCode(),groupMember.getGroupName().getName());
259    //                      gmi.setMemberId(group.getGroupId());
260    //                      gmi.setMemberTypeCode(KimGroupMemberTypes.GROUP_MEMBER_TYPE);
261    //              }
262    //              
263    //              /**
264    //            if (principal != null) {
265    //                addPrincipalToGroup(groupInfo.getNamespaceCode(), groupInfo.getGroupName(), principal.getPrincipalId());
266    //            } else {
267    //                throw new InvalidXmlException("Principal Name "+principalName+" cannot be found.");
268    //            }
269    //            **/
270    //    
271    //        }
272    //      
273    //      return gi;
274    //    }
275    // 
276        private boolean isBlank(Object o){
277            return (o == null || "".equals(o));
278        }
279            
280        
281        public class DataNamespaceURIFilter extends XMLFilterImpl {
282    
283            public static final String DATA_URI=CoreNamespaceConstants.CORE;
284            
285            public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException {
286                if("data".equals(localName)) {
287                    uri = DATA_URI;
288                }
289                
290                super.startElement(uri, localName, qName, atts);
291            }
292    
293            public void endElement(String uri, String localName, String qName) throws SAXException {
294                if(StringUtils.isBlank(uri)) {
295                    uri = DATA_URI;
296                }
297                
298                super.endElement(uri, localName, qName);
299            }
300        }
301    
302    }