001    package railo.runtime.text.feed;
002    
003    import java.io.IOException;
004    import java.io.InputStream;
005    
006    import org.xml.sax.Attributes;
007    import org.xml.sax.InputSource;
008    import org.xml.sax.Locator;
009    import org.xml.sax.SAXException;
010    import org.xml.sax.XMLReader;
011    import org.xml.sax.ext.Locator2;
012    import org.xml.sax.helpers.DefaultHandler;
013    
014    import railo.commons.io.IOUtil;
015    import railo.commons.io.SystemUtil;
016    import railo.commons.io.res.Resource;
017    import railo.commons.lang.StringUtil;
018    import railo.runtime.exp.DatabaseException;
019    import railo.runtime.exp.PageException;
020    import railo.runtime.text.xml.XMLUtil;
021    import railo.runtime.type.Collection;
022    import railo.runtime.type.Collection.Key;
023    import railo.runtime.type.KeyImpl;
024    import railo.runtime.type.Query;
025    import railo.runtime.type.QueryImpl;
026    import railo.runtime.type.Struct;
027    import railo.runtime.type.StructImpl;
028    
029    public final class RSSHandler extends DefaultHandler {
030            
031            public final static String DEFAULT_SAX_PARSER="org.apache.xerces.parsers.SAXParser";
032    
033            private static final Key RSSLINK = KeyImpl.intern("RSSLINK");
034            private static final Key CONTENT = KeyImpl.intern("CONTENT");
035    
036            private static final Key LINK = KeyImpl.intern("LINK");
037            private static final Key DESCRIPTION = KeyImpl.intern("DESCRIPTION");
038            
039            private static Collection.Key[] COLUMNS=new Collection.Key[]{
040                    KeyImpl.intern("AUTHOREMAIL"),
041                    KeyImpl.intern("AUTHORNAME"),
042                    KeyImpl.intern("AUTHORURI"),
043                    KeyImpl.intern("CATEGORYLABEL"),
044                    KeyImpl.intern("CATEGORYSCHEME"),
045                    KeyImpl.intern("CATEGORYTERM"),
046                    KeyImpl.intern("COMMENTS"),
047                    CONTENT,
048                    KeyImpl.intern("CONTENTMODE"),
049                    KeyImpl.intern("CONTENTSRC"),
050                    KeyImpl.intern("CONTENTTYPE"),
051                    KeyImpl.intern("CONTRIBUTOREMAIL"),
052                    KeyImpl.intern("CONTRIBUTORNAME"),
053                    KeyImpl.intern("CONTRIBUTORURI"),
054                    KeyImpl.intern("CREATEDDATE"),
055                    KeyImpl.intern("EXPIRATIONDATE"),
056                    KeyImpl.intern("ID"),
057                    KeyImpl.intern("IDPERMALINK"),
058                    KeyImpl.intern("LINKHREF"),
059                    KeyImpl.intern("LINKHREFLANG"),
060                    KeyImpl.intern("LINKLENGTH"),
061                    KeyImpl.intern("LINKREL"),
062                    KeyImpl.intern("LINKTITLE"),
063                    KeyImpl.intern("LINKTYPE"),
064                    KeyImpl.intern("PUBLISHEDDATE"),
065                    KeyImpl.intern("RIGHTS"),
066                    RSSLINK,
067                    KeyImpl.intern("SOURCE"),
068                    KeyImpl.intern("SOURCEURL"),
069                    KeyImpl.intern("SUMMARY"),
070                    KeyImpl.intern("SUMMARYMODE"),
071                    KeyImpl.intern("SUMMARYSRC"),
072                    KeyImpl.intern("SUMMARYTYPE"),
073                    KeyImpl.intern("TITLE"),
074                    KeyImpl.intern("TITLETYPE"),
075                    KeyImpl.intern("UPDATEDDATE"),
076                    KeyImpl.intern("URI"),
077                    KeyImpl.intern("XMLBASE")
078            };
079            
080            
081            private XMLReader xmlReader;
082    
083            private String lcInside;
084            private StringBuffer content=new StringBuffer();
085    
086            private boolean insideImage;
087            private boolean insideItem;
088    
089            private Struct image;
090            private Struct properties;
091            private Query items;
092    
093            private Collection.Key inside;
094            
095            /**
096             * Constructor of the class
097             * @param res
098             * @throws IOException
099             * @throws SAXException 
100             * @throws DatabaseException 
101             */
102            public RSSHandler(Resource res) throws IOException, SAXException, DatabaseException {
103                    InputStream is=null;
104                    try {
105                            InputSource source=new InputSource(is=res.getInputStream());
106                            source.setSystemId(res.getPath());
107                            init(DEFAULT_SAX_PARSER,source);
108                    } 
109                    finally {
110                            IOUtil.closeEL(is);
111                    }
112            }
113    
114            /**
115             * Constructor of the class
116             * @param stream
117             * @throws IOException
118             * @throws SAXException 
119             * @throws DatabaseException 
120             */
121            public RSSHandler(InputStream stream) throws IOException, SAXException, DatabaseException {
122                    InputSource is=new InputSource(IOUtil.getReader(stream, SystemUtil.getCharset()));
123                    init(DEFAULT_SAX_PARSER,is);
124            }
125            
126            private void init(String saxParser,InputSource is) throws SAXException, IOException, DatabaseException  {
127                    properties=new StructImpl();
128                    items=new QueryImpl(COLUMNS,0,"query");
129                    xmlReader=XMLUtil.createXMLReader(saxParser);
130                    xmlReader.setContentHandler(this);
131                    xmlReader.setErrorHandler(this);
132                    
133                    //xmlReader.setEntityResolver(new TagLibEntityResolver());
134                    xmlReader.parse(is);
135                    
136                    //properties.setEL("encoding",is.getEncoding());
137                    
138        }
139            
140            public void setDocumentLocator(Locator locator) { 
141                      if (locator instanceof Locator2) {
142                        Locator2 locator2 = (Locator2) locator;
143                        properties.setEL("encoding", locator2.getEncoding());
144                      } 
145                    }
146    
147            @Override
148            public void startElement(String uri, String name, String qName, Attributes atts) {
149                    inside = KeyImpl.getInstance(qName);
150                    lcInside=qName.toLowerCase();
151                    if(lcInside.equals("image"))            insideImage=true;
152                    else if(qName.equals("item"))   {
153                            items.addRow();
154                            insideItem=true;
155                    }
156                    else if(lcInside.equals("rss"))         {
157                            String version = atts.getValue("version");
158                            if(!StringUtil.isEmpty(version))
159                                    properties.setEL("version", "rss_"+version);
160                    }
161                    
162                    /* / cloud
163                    else if(!insideItem && lcInside.equals("cloud"))        {
164                            
165                            
166                            
167                            String url = atts.getValue("url");
168                            if(!StringUtil.isEmpty(url))items.setAtEL("LINKHREF", items.getRowCount(), url);
169                            String length = atts.getValue("length");
170                            if(!StringUtil.isEmpty(length))items.setAtEL("LINKLENGTH", items.getRowCount(), length);
171                            String type = atts.getValue("type");
172                            if(!StringUtil.isEmpty(type))items.setAtEL("LINKTYPE", items.getRowCount(), type);
173                    }*/
174                    
175                    
176                    // enclosure
177                    else if(insideItem && lcInside.equals("enclosure"))     {
178                            String url = atts.getValue("url");
179                            if(!StringUtil.isEmpty(url))items.setAtEL("LINKHREF", items.getRowCount(), url);
180                            String length = atts.getValue("length");
181                            if(!StringUtil.isEmpty(length))items.setAtEL("LINKLENGTH", items.getRowCount(), length);
182                            String type = atts.getValue("type");
183                            if(!StringUtil.isEmpty(type))items.setAtEL("LINKTYPE", items.getRowCount(), type);
184                    }
185                    
186                    else if(atts.getLength()>0) {
187                            int len=atts.getLength();
188                            Struct sct=new StructImpl();
189                            for(int i=0;i<len;i++) {
190                                    sct.setEL(atts.getQName(i), atts.getValue(i));
191                            }
192                            properties.setEL(inside, sct);
193                    }
194                    
195                    //<enclosure url="http://www.scripting.com/mp3s/weatherReportDicksPicsVol7.mp3" length="6182912" type="audio/mpeg"/>
196            }
197        
198            @Override
199            public void endElement(String uri, String name, String qName) {
200                    setContent(content.toString().trim());
201                    content=new StringBuffer();
202                    inside=null;
203                    lcInside="";
204                    
205                    if(qName.equals("image")) insideImage=false;
206                    if(qName.equals("item")) insideItem=false;
207            }
208            
209            
210        @Override
211            public void characters (char ch[], int start, int length)       {
212                    content.append(new String(ch,start,length));
213            }
214            
215            private void setContent(String value)   {
216                    if(StringUtil.isEmpty(lcInside)) return;
217                    
218                    if(insideImage) {
219                            if(image==null){
220                                    image=new StructImpl();
221                                    properties.setEL("image",image);
222                            }
223                            image.setEL(inside,value);
224                    }
225                    else if(insideItem)     {
226                            try {
227                                    items.setAt(toItemColumn(inside), items.getRowCount(), value);
228                            } catch (PageException e) {
229                                    //print.err(inside);
230                            }
231                            
232                    }
233                    else {
234                            if(!(StringUtil.isEmpty(value,true) && properties.containsKey(inside)))
235                                    properties.setEL(inside,value);
236                    }       
237        }
238    
239            private Collection.Key toItemColumn(Collection.Key key) {
240                    if(key.equalsIgnoreCase(LINK))                  return RSSLINK;
241                    else if(key.equalsIgnoreCase(DESCRIPTION))return CONTENT;
242                    return key;
243            }
244    
245            /**
246             * @return the properties
247             */
248            public Struct getProperties() {
249                    return properties;
250            }
251    
252            /**
253             * @return the items
254             */
255            public Query getItems() {
256                    return items;
257            }
258            
259            
260            /*public static void main(String[] args) throws IOException, SAXException {
261                    ResourceProvider frp = ResourcesImpl.getFileResourceProvider();
262                    Resource res = frp.getResource("/Users/mic/Projects/Railo/webroot/jm/feed/092.xml");
263                    RSSHandler rss=new RSSHandler(res);
264                    print.out(rss.getProperties());
265                    print.out(rss.getItems());
266                    
267            }*/
268    }