View Javadoc

1   /*
2    * Copyright (c) 2007, James Leigh All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    * 
7    * - Redistributions of source code must retain the above copyright notice, this
8    *   list of conditions and the following disclaimer.
9    * - Redistributions in binary form must reproduce the above copyright notice,
10   *   this list of conditions and the following disclaimer in the documentation
11   *   and/or other materials provided with the distribution. 
12   * - Neither the name of the openrdf.org nor the names of its contributors may
13   *   be used to endorse or promote products derived from this software without
14   *   specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * 
28   */
29  package org.openrdf.elmo.sesame;
30  
31  import java.io.File;
32  import java.io.IOException;
33  import java.io.InputStream;
34  import java.net.URL;
35  import java.util.ArrayList;
36  import java.util.Enumeration;
37  import java.util.HashMap;
38  import java.util.List;
39  import java.util.Map;
40  
41  import javax.persistence.PersistenceException;
42  import javax.persistence.spi.PersistenceProvider;
43  import javax.persistence.spi.PersistenceUnitInfo;
44  import javax.xml.parsers.DocumentBuilder;
45  import javax.xml.parsers.DocumentBuilderFactory;
46  import javax.xml.parsers.ParserConfigurationException;
47  
48  import org.openrdf.elmo.ElmoModule;
49  import org.w3c.dom.Document;
50  import org.w3c.dom.Element;
51  import org.w3c.dom.Node;
52  import org.w3c.dom.NodeList;
53  import org.w3c.dom.Text;
54  import org.xml.sax.SAXException;
55  
56  /**
57   * Used in META-INF/persistence.xml to indicate a SesameManager should be
58   * used.
59   * 
60   * @author James Leigh
61   * 
62   */
63  public class SesamePersistenceProvider implements PersistenceProvider {
64  	/** persistence.xml */
65  	public final static String PERSISTENCE_XML = "META-INF/persistence.xml";
66  
67  	private static final String PROVIDER_NAME = SesamePersistenceProvider.class.getName();
68  
69  	public SesameManagerFactory createContainerEntityManagerFactory(
70  			PersistenceUnitInfo info, Map map) {
71  		if (!PROVIDER_NAME.equals(info.getPersistenceProviderClassName()))
72  			return null;
73  		try {
74  			ClassLoader cl = info.getClassLoader();
75  			List<String> names = info.getManagedClassNames();
76  			List<Class<?>> types = new ArrayList<Class<?>>(names.size());
77  			for (String name : names) {
78  				types.add(Class.forName(name, true, cl));
79  			}
80  			Map props = new HashMap();
81  			props.putAll(info.getProperties());
82  			if (map != null) {
83  				props.putAll(map);
84  			}
85  			return createSesameManagerFactory(props, types);
86  		} catch (Exception e) {
87  			throw new PersistenceException(e);
88  		}
89  	}
90  
91  	public SesameManagerFactory createEntityManagerFactory(String emName,
92  			Map map) {
93  		try {
94  			Element unit = findPresistenceUnit(emName);
95  			NodeList providers = unit.getElementsByTagName("provider");
96  			if (providers.getLength() > 0) {
97  				Element provider = (Element) providers.item(0);
98  				if (!PROVIDER_NAME.equals(getTextContent(provider)))
99  					return null;
100 			}
101 			ClassLoader cl = Thread.currentThread().getContextClassLoader();
102 			NodeList names = unit.getElementsByTagName("class");
103 			List<Class<?>> types = new ArrayList<Class<?>>(names.getLength());
104 			for (int i = 0, n = names.getLength(); i < n; i++) {
105 				String name = getTextContent(names.item(i));
106 				types.add(Class.forName(name, true, cl));
107 			}
108 			Map props = new HashMap();
109 			props.putAll(getProperties(unit));
110 			if (map != null) {
111 				props.putAll(map);
112 			}
113 			return createSesameManagerFactory(props, types);
114 		} catch (Exception e) {
115 			throw new PersistenceException(e);
116 		}
117 	}
118 
119 	private String getTextContent(Node node) {
120 		node.normalize();
121 		Text text = (Text) node.getFirstChild();
122 		return text.getData().trim();
123 	}
124 
125 	private SesameManagerFactory createSesameManagerFactory(
126 			Map<String, String> props, List<Class<?>> types) throws Exception {
127 		ElmoModule module = new ElmoModule();
128 		if (types != null) {
129 			for (Class<?> type : types) {
130 				module.recordRole(type);
131 			}
132 		}
133 		if (props.containsKey("resources")) {
134 			String resources = props.get("resources");
135 			for (String resource : resources.trim().split("[,\\s]+")) {
136 				module.addResources(resource);
137 			}
138 		}
139 		return createSesameManagerFactory(module, props);
140 	}
141 
142 	private SesameManagerFactory createSesameManagerFactory(ElmoModule module,
143 			Map<String, String> props) throws Exception {
144 		String id = props.get("repositoryId");
145 		if (id != null && props.containsKey("dataDir")) {
146 			File dataDir = new File(props.get("dataDir"));
147 			return new SesameManagerFactory(module, dataDir, id);
148 		}
149 		if (id != null && props.containsKey("serverUrl")) {
150 			URL server = new URL(props.get("serverUrl"));
151 			return new SesameManagerFactory(module, server, id);
152 		}
153 		if (id != null && props.containsKey("applicationId")) {
154 			String appId = props.get("applicationId");
155 			return new SesameManagerFactory(module, appId, id);
156 		}
157 		return new SesameManagerFactory(module);
158 	}
159 
160 	private Element findPresistenceUnit(String emName) throws SAXException,
161 			IOException, ParserConfigurationException {
162 		ClassLoader cl = Thread.currentThread().getContextClassLoader();
163 		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
164 		DocumentBuilder parser = dbf.newDocumentBuilder();
165 		Enumeration<URL> resources = cl.getResources(PERSISTENCE_XML);
166 		while (resources.hasMoreElements()) {
167 			URL url = resources.nextElement();
168 			InputStream stream = url.openStream();
169 			try {
170 				Document doc = parser.parse(stream);
171 				NodeList list = doc.getElementsByTagName("persistence-unit");
172 				for (int i = 0, n = list.getLength(); i < n; i++) {
173 					Element item = (Element) list.item(i);
174 					if (emName.equals(item.getAttribute("name")))
175 						return item;
176 				}
177 			} finally {
178 				stream.close();
179 			}
180 		}
181 		throw new IllegalArgumentException(
182 				"Cannot find persistence-unit with name: " + emName);
183 	}
184 
185 	private Map<String, String> getProperties(Element unit) {
186 		Map<String, String> properties = new HashMap<String, String>();
187 		NodeList list = unit.getElementsByTagName("property");
188 		for (int i = 0, n = list.getLength(); i < n; i++) {
189 			Element item = (Element) list.item(i);
190 			properties.put(item.getAttribute("name"), item
191 					.getAttribute("value"));
192 		}
193 		return properties;
194 	}
195 
196 }