1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 package info.magnolia.module.googlesitemap.service;
35
36 import info.magnolia.module.googlesitemap.SiteMapNodeTypes;
37 import info.magnolia.module.googlesitemap.bean.SiteMapEntry;
38 import info.magnolia.module.googlesitemap.bean.SiteMapEntryList;
39 import info.magnolia.module.googlesitemap.config.SiteMapType;
40
41 import java.io.StringWriter;
42 import java.util.ArrayList;
43 import java.util.Iterator;
44 import java.util.List;
45 import java.util.Stack;
46
47 import javax.inject.Provider;
48 import javax.inject.Singleton;
49 import javax.jcr.Node;
50 import javax.jcr.RepositoryException;
51 import javax.xml.bind.JAXBContext;
52 import javax.xml.bind.JAXBException;
53 import javax.xml.bind.Marshaller;
54 import javax.xml.bind.PropertyException;
55 import javax.xml.stream.XMLOutputFactory;
56 import javax.xml.stream.XMLStreamException;
57 import javax.xml.stream.XMLStreamWriter;
58
59 import org.slf4j.Logger;
60 import org.slf4j.LoggerFactory;
61
62 import com.google.inject.Inject;
63
64
65
66
67 @Singleton
68 public class SiteMapXMLUtilImpl implements SiteMapXMLUtil {
69
70 public static final String MOBILE_SCHEMA_URL = "http://www.google.com/schemas/sitemap-mobile/1.0";
71
72
73
74
75
76 public static final String MOBILE_ELEMENT_NAME = "mobile";
77
78 public static final String MOBILE_PREFIX = "mobile";
79
80 public static final String URL_ELEMENT_NAME = "url";
81
82 private Logger log = LoggerFactory.getLogger(getClass());
83
84 private Provider<SiteMapService> service;
85
86 @Inject
87 public SiteMapXMLUtilImpl(Provider<SiteMapService> service) {
88 this.service = service;
89 }
90
91
92
93
94
95
96
97 @Override
98 public String generateSiteMapXML(Node siteMapNode) throws RepositoryException, JAXBException {
99 List<SiteMapEntry> entries = new ArrayList<SiteMapEntry>();
100 Iterator<SiteMapEntry> entryIt = service.get().getSiteMapBeans(siteMapNode);
101 while (entryIt.hasNext()) {
102 entries.add(entryIt.next());
103 }
104 String type = SiteMapNodeTypes.SiteMap.getType(siteMapNode) != null ? SiteMapNodeTypes.SiteMap.getType(siteMapNode) : SiteMapType.Standard.name();
105 return marshalSiteMapEntries(entries, SiteMapType.valueOf(type));
106 }
107
108 private String marshalSiteMapEntries(List<SiteMapEntry> entries, final SiteMapType type) throws JAXBException {
109 JAXBContext jaxbContext = JAXBContext.newInstance(SiteMapEntry.class, SiteMapEntryList.class);
110 StringWriter sw = new StringWriter();
111 Marshaller marshaller = jaxbContext.createMarshaller();
112 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
113 marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
114
115 try {
116 SiteMapEntryList list = new SiteMapEntryList(entries);
117 final XMLStreamWriter writer = XMLOutputFactory.newInstance().createXMLStreamWriter(sw);
118 final XMLStreamWriter delWriter = new DelegatingXMLStreamWriter(writer) {
119 Stack<String> namespaceStack = new Stack<>();
120
121 @Override
122 public void writeStartElement(String prefix, String namespace, String localName) throws XMLStreamException {
123 super.writeStartElement(prefix, namespace, localName);
124 namespaceStack.push(namespace);
125 }
126
127 @Override
128 public void writeEndElement() throws XMLStreamException {
129 if (URL_ELEMENT_NAME.equals(namespaceStack.pop()) && SiteMapType.Mobile == type) {
130 writeEmptyElement(MOBILE_PREFIX, MOBILE_ELEMENT_NAME, "");
131 }
132 super.writeEndElement();
133 }
134
135 @Override
136 public void writeNamespace(String prefix, String localName) throws XMLStreamException {
137 super.writeNamespace(prefix, localName);
138 if (type == SiteMapType.Mobile) {
139 super.writeNamespace(MOBILE_PREFIX, MOBILE_SCHEMA_URL);
140 }
141 }
142 };
143 marshaller.marshal(list, delWriter);
144 } catch (PropertyException e) {
145 log.error("Failed to rebind marshaller's namespace prefix mapper, did the implementation of JAXB change?", e);
146 } catch (XMLStreamException e) {
147 log.error("Failed to marshal sitemap", e);
148 }
149 return sw.toString();
150 }
151
152 }