OpenJPA-1610: Added XMLVersionParser from trunk and logic in PersistenceProductDerivation to use it. This allows OpenJPA 1.1.x to play well with JPA 2.0 providers by accepting that it cannot service any persistence unit that uses a persistence.xml whose version is not "1.0".

Also altered POMs to decline external and dated Xerces parser dependency and use instead the Xerces parser of the JDK for the OpenJPA test cases.

git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/1.1.x@957329 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
David Ezzio 2010-06-23 20:23:28 +00:00
parent e14849f32a
commit 2516f52291
13 changed files with 544 additions and 7 deletions

View File

@ -48,6 +48,13 @@
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<scope>test</scope>
<!-- exclude Xerces used by this module and use only XERCES from the JDK -->
<exclusions>
<exclusion>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-collections</groupId>

View File

@ -0,0 +1,85 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.lib.meta;
import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
/**
* Custom non-validating SAX parser which can be used to get the version and
* schema location attributes from the root node.
*
* @author Jeremy Bauer
* @nojavadoc
*/
public class XMLVersionParser extends XMLMetaDataParser {
public static final String VERSION_1_0 = "1.0";
public static final String VERSION_2_0 = "2.0";
static private final String VERSION_ATTR = "version";
static private final String XSI_NS =
"http://www.w3.org/2001/XMLSchema-instance";
static private final String SCHEMA_LOCATION = "schemaLocation";
private String _rootElement;
private String _version;
private String _schemaLocation;
public XMLVersionParser(String rootElement) {
_rootElement = rootElement;
setCaching(false);
setValidating(false);
setParseText(false);
}
@Override
protected void endElement(String name) throws SAXException {
}
@Override
protected boolean startElement(String name, Attributes attrs)
throws SAXException {
if (name.equals(_rootElement)) {
// save the version and schema location attributes
_version = attrs.getValue("", VERSION_ATTR);
_schemaLocation = attrs.getValue(XSI_NS, SCHEMA_LOCATION);
// ignore remaining content
ignoreContent(true);
}
return false;
}
/**
* Get the string value of the version attribute on the root element
* @return doc version
*/
public String getVersion() {
return _version;
}
/**
* Get the string value of the schema location attribute on the root element
* @return doc schema location
*/
public String getSchemaLocation() {
return _schemaLocation;
}
}

View File

@ -254,6 +254,13 @@
<artifactId>commons-dbcp</artifactId>
<version>1.2.1</version>
<scope>test</scope>
<!-- exclude Xerces used by this module and use only XERCES from the JDK -->
<exclusions>
<exclusion>
<groupId>xerces</groupId>
<artifactId>xerces</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>commons-collections</groupId>

View File

@ -0,0 +1,48 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence;
import java.io.ByteArrayOutputStream;
public class CaptureStream extends ByteArrayOutputStream {
public boolean contains(String str) {
if (str == null)
return false;
if (str.length() == 0)
return true;
boolean retv = false;
byte [] bytes = str.getBytes();
// search by brute force
KeepSearching: for (int x = 0; x < buf.length; x++) {
for (int y = 0; y < bytes.length; y++) {
if (bytes[y] != buf[x + y])
// not here, keep searching
continue KeepSearching;
}
// found it
retv = true;
break;
}
return retv;
}
}

View File

@ -0,0 +1,58 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence;
import java.io.IOException;
import java.io.PrintStream;
public class ViewStream extends PrintStream {
private CaptureStream captureStream;
private PrintStream original;
public ViewStream(PrintStream original) {
super(original);
this.original = original;
this.captureStream = new CaptureStream();
}
@Override
public void flush() {
super.flush();
try {
captureStream.flush();
} catch (IOException e) {
// do nothing
}
}
@Override
public void write(byte[] buf, int off, int len) {
super.write(buf, off, len);
captureStream.write(buf, off, len);
}
public PrintStream getOriginal() {
return original;
}
public boolean contains(String str) {
return captureStream.contains(str);
}
}

View File

@ -0,0 +1,111 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.persistence.xml;
import java.util.MissingResourceException;
import javax.persistence.EntityManager;
import junit.framework.TestCase;
import org.apache.openjpa.persistence.ViewStream;
import org.apache.openjpa.persistence.OpenJPAEntityManager;
import org.apache.openjpa.persistence.OpenJPAEntityManagerFactory;
import org.apache.openjpa.persistence.OpenJPAPersistence;
/**
* These test cases come from the branch of OpenJPA that implements JPA 2.0.
* The purpose here is simply to ensure that no 2.0 persistence.xml will fail
* to be detected.
*/
public class TestSchemaVersionValidation extends TestCase {
private ViewStream viewStream;
@Override
protected void setUp() throws Exception {
System.setErr(viewStream = new ViewStream(System.err));
}
@Override
protected void tearDown() throws Exception {
if (viewStream != null)
System.setErr(viewStream.getOriginal());
}
/**
* Verify that a null will be returned and an informative error message will be
* issued when attempting to read a Version 2.0 persistence.xml document
*/
public void test2_0PersistenceXml() {
OpenJPAEntityManagerFactory emf = null;
try {
emf = OpenJPAPersistence.createEntityManagerFactory("XSDTest",
"org/apache/openjpa/persistence/xml/persistence-2_0.xml");
fail("Did not throw exception");
} catch (MissingResourceException e) {
// expected
} finally {
if (emf != null)
emf.close();
}
assertTrue("Did not find expected warning in System.err print stream",
viewStream.contains("This version of OpenJPA cannot read a " +
"persistence.xml document with a version different from \"1.0\""));
}
/**
* Verify that we will get back a null EMF if we attempt to load a
* 2.0 ORM within a 1.0 persistence.xml.
*/
public void test1_0Persistence2_0OrmXml() {
OpenJPAEntityManagerFactory emf = null;
try {
emf = OpenJPAPersistence.createEntityManagerFactory("XSDTest",
"org/apache/openjpa/persistence/xml/persistence-2_0-orm-1_0.xml");
assertNull(emf);
} finally {
if (emf != null)
emf.close();
}
}
/**
* Verify that a persistence.xml document without a version tag will be flagged
* as non-conforming.
*/
public void testPersistenceWithoutVersion() {
OpenJPAEntityManagerFactory emf = null;
try {
emf = OpenJPAPersistence.createEntityManagerFactory("XSDTest",
"org/apache/openjpa/persistence/xml/persistence-no-version.xml");
} catch (MissingResourceException e) {
// expected
} finally {
if (emf != null)
emf.close();
}
assertTrue("Did not find expected warning in error stream",
viewStream.contains("This version of OpenJPA cannot read a " +
"persistence.xml document with a version different from \"1.0\""));
}
}

View File

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<entity-mappings xmlns="http://java.sun.com/xml/ns/persistence/orm"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm orm_2_0.xsd"
version="2.0">
<persistence-unit-metadata>
<persistence-unit-defaults>
<description> This is an orm 2.0 element</description>
</persistence-unit-defaults>
</persistence-unit-metadata>
<package>
org.apache.openjpa.persistence.xml
</package>
<entity name="SimpleXml" class="SimpleXmlEntity">
<named-query name="SimpleXml.findAll">
<query>select o from SimpleXml o</query>
</named-query>
<named-query name="SimpleXmlEntity.findAll">
<query>select o from SimpleXmlEntity o</query>
</named-query>
<attributes>
<id name="id">
<generated-value generator="uuid-hex"/>
</id>
<basic name="stringField"/>
<version name="version"/>
</attributes>
</entity>
</entity-mappings>

View File

@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
version="1.0" >
<persistence-unit name="XSDTest" transaction-type="RESOURCE_LOCAL">
<description>PU for schema validation testing</description>
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
<mapping-file>org/apache/openjpa/persistence/xml/orm_2_0.xml</mapping-file>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd"
version="2.0" >
<persistence-unit name="XSDTest" transaction-type="RESOURCE_LOCAL">
<description>PU for schema validation testing</description>
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
</persistence-unit>
</persistence>

View File

@ -0,0 +1,29 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
-->
<persistence
xmlns="http://java.sun.com/xml/ns/persistence"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
>
<persistence-unit name="XSDTest" transaction-type="RESOURCE_LOCAL">
<description>PU for schema validation testing</description>
<provider>org.apache.openjpa.persistence.PersistenceProviderImpl</provider>
</persistence-unit>
</persistence>

View File

@ -45,6 +45,7 @@ import org.apache.openjpa.lib.conf.MapConfigurationProvider;
import org.apache.openjpa.lib.conf.ProductDerivations;
import org.apache.openjpa.lib.log.Log;
import org.apache.openjpa.lib.meta.XMLMetaDataParser;
import org.apache.openjpa.lib.meta.XMLVersionParser;
import org.apache.openjpa.lib.util.J2DoPrivHelper;
import org.apache.openjpa.lib.util.Localizer;
import org.xml.sax.Attributes;
@ -192,6 +193,8 @@ public class PersistenceProductDerivation
throws IOException {
if (!file.getName().endsWith(".xml"))
return null;
if (!isVersionOnePersistenceDoc(file))
return null;
ConfigurationParser parser = new ConfigurationParser(null);
parser.parse(file);
@ -206,6 +209,9 @@ public class PersistenceProductDerivation
@Override
public List getAnchorsInFile(File file) throws IOException {
if (!isVersionOnePersistenceDoc(file))
return null;
ConfigurationParser parser = new ConfigurationParser(null);
try {
parser.parse(file);
@ -233,7 +239,8 @@ public class PersistenceProductDerivation
List<URL> urls = getResourceURLs(resource, loader);
if (urls != null) {
for (URL url : urls) {
parser.parse(url);
if (isVersionOnePersistenceDoc(url))
parser.parse(url);
}
}
return getUnitNames(parser);
@ -356,8 +363,10 @@ public class PersistenceProductDerivation
List<PersistenceUnitInfoImpl> pinfos =
new ArrayList<PersistenceUnitInfoImpl>();
for (URL url : urls) {
parser.parse(url);
pinfos.addAll((List<PersistenceUnitInfoImpl>) parser.getResults());
if (isVersionOnePersistenceDoc(url)) {
parser.parse(url);
pinfos.addAll((List<PersistenceUnitInfoImpl>) parser.getResults());
}
}
return findUnit(pinfos, name, loader);
}
@ -431,6 +440,78 @@ public class PersistenceProductDerivation
System.err.println(msg);
}
/**
* Return true if the version is specified as version "1.0".
* Return false if it is specified as anything else
*
* By calling this method, the caller can avoid parsing
* persistence.xml documents that are some other version.
*/
public boolean isVersionOnePersistenceDoc(URL url) {
// default return value
boolean retv = true;
// peek at the doc to determine the version
XMLVersionParser vp = new XMLVersionParser("persistence");
try {
vp.parse(url);
String versionStr = vp.getVersion();
// if the versionStr is not equal to "1.0" return false
if (!XMLVersionParser.VERSION_1_0.equals(versionStr)) {
retv = false;
log(_loc.get("version-limitation", (versionStr == null ? "" : versionStr),
url.toString()).getMessage());
}
} catch (Exception t) {
String msg = "Exception: " + t.getClass().getName() + ": ";
String m = t.getLocalizedMessage();
msg += (StringUtils.isEmpty(m) ? "" : (": " + m));
log(_loc.get("version-check-error", msg, url.toString()).getMessage());
// return true and allow processing to continue
// additional processing will likely lead to a more informative error message
}
return retv;
}
/**
* Return true if the version is specified as version "1.0".
* Return false if it is specified as anything else
*
* By calling this method, the caller can avoid parsing
* persistence.xml documents that are some other version.
*/
public boolean isVersionOnePersistenceDoc(File file) {
// default return value
boolean retv = true;
// peek at the doc to determine the version
XMLVersionParser vp = new XMLVersionParser("persistence");
try {
vp.parse(file);
String versionStr = vp.getVersion();
// if the versionStr is not equal to "1.0" return false
if (!XMLVersionParser.VERSION_1_0.equals(versionStr)) {
retv = false;
log(_loc.get("version-limitation", (versionStr == null ? "" : versionStr),
file.toString()).getMessage());
}
} catch (Exception t) {
String msg = "Exception: " + t.getClass().getName() + ": ";
String m = t.getLocalizedMessage();
msg += (StringUtils.isEmpty(m) ? "" : (": " + m));
log(_loc.get("version-check-error", msg, file.toString()).getMessage());
// return true and allow processing to continue
// additional processing will likely lead to a more informative error message
}
return retv;
}
/**
* Custom configuration provider.
*/
@ -604,6 +685,6 @@ public class PersistenceProductDerivation
if (_source != null)
_info.setPersistenceXmlFileUrl(_source);
}
}
}
}
}

View File

@ -209,5 +209,5 @@ public class PersistenceProviderImpl
throws IllegalClassFormatException {
return _trans.transform(cl, name, previousVersion, pd, bytes);
}
}
}
}

View File

@ -80,7 +80,8 @@ naming-exception: A NamingException was thrown while obtaining the \
factory at "{0}" from JNDI.
bad-jar-name: The jar resource "{0}" cannot be loaded.
missing-xml-config: The specified XML resource "{0}" for persistence unit \
"{1}" can''t be found in your class path.
"{1}" can''t be found in your class path, or it was found but does not have a \
"1.0" version.
cantload-xml-config: The specified XML resource "{0}" for persistence unit \
"{1}" can''t be parsed.
unknown-provider: Persistence provider "{2}" specified in persistence unit \
@ -135,6 +136,10 @@ transformer-registration-error: An error occurred while registering a \
transformer-registration-error-ex: An error occurred while registering a \
ClassTransformer with {0}. The error is logged along with this warning. \
Load-time class transformation will not be available.
version-check-error: The exception "{0}" occurred while attempting to determine the \
version of "{1}".
version-limitation: This version of OpenJPA cannot read a persistence.xml document \
with a version different from "1.0". Found: version "{0}" in "{1}".
EntityManagerFactory-name: EntityManagerFactory implementation
EntityManagerFactory-desc: Allows extension of standard \