Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

JBOSGI-794 WAB Fragment resources are not available through host #24

Merged
merged 1 commit into from May 17, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Expand Up @@ -73,8 +73,11 @@ public class WebAppTestCase {
static final String BUNDLE_D_WAB = "bundle-d.wab";
static final String BUNDLE_E_JAR = "bundle-e.jar";
static final String BUNDLE_F_WAB = "bundle-f.wab";
static final String BUNDLE_G_HOST_JAR = "bundle-g.jar";
static final String BUNDLE_H_FRAG_JAR = "bundle-h.jar";

static final Asset STRING_ASSET = new StringAsset("Hello from Resource");
static final Asset STRING_FRAG_ASSET = new StringAsset("Hello from Fragment Resource");

@ArquillianResource
Deployer deployer;
Expand Down Expand Up @@ -197,6 +200,82 @@ public void testSimpleBundleWithJarExtension() throws Exception {
}
}

@Test
// JBOSGI-794
public void testFragmentAndHostBundleWithJarExtension() throws Exception {
// Fragment is started then host is started
deployer.deploy(BUNDLE_H_FRAG_JAR);
try {
deployer.deploy(BUNDLE_G_HOST_JAR);
try {
String result = performCall("/bundle-g/servlet?input=Hello");
Assert.assertEquals("Simple Servlet called with input=Hello", result);
result = performCall("/bundle-g/message.txt");
Assert.assertEquals("Hello from Resource", result);
result = performCall("/bundle-g/message-frag.txt");
Assert.assertEquals("Hello from Fragment Resource", result);
} finally {
deployer.undeploy(BUNDLE_G_HOST_JAR);
}
} finally {
deployer.undeploy(BUNDLE_H_FRAG_JAR);
}
}

@Test
// JBOSGI-794
public void testHostBundleAndFragmentWithJarExtension() throws Exception {
// Bundle is installed but not started, then fragment is started
InputStream input = deployer.getDeployment(BUNDLE_G_HOST_JAR);
Bundle bundle = context.installBundle(BUNDLE_G_HOST_JAR, input);
try {
Assert.assertEquals("INSTALLED", Bundle.INSTALLED, bundle.getState());
deployer.deploy(BUNDLE_H_FRAG_JAR);
bundle.start();
Assert.assertEquals("ACTIVE", Bundle.ACTIVE, bundle.getState());
try {
String result = performCall("/bundle-g/servlet?input=Hello");
Assert.assertEquals("Simple Servlet called with input=Hello", result);
result = performCall("/bundle-g/message.txt");
Assert.assertEquals("Hello from Resource", result);
result = performCall("/bundle-g/message-frag.txt");
Assert.assertEquals("Hello from Fragment Resource", result);
} finally {
deployer.undeploy(BUNDLE_H_FRAG_JAR);
}
} finally {
deployer.undeploy(BUNDLE_G_HOST_JAR);
}
}

@Test
// JBOSGI-794
public void testHostBundleAndFragmentWithJarExtensionSimulateConcurrentStartup() throws Exception {
// Bundle is installed, fragment is installed, then host is started
InputStream input = deployer.getDeployment(BUNDLE_G_HOST_JAR);
Bundle hostBundle = context.installBundle(BUNDLE_G_HOST_JAR, input);
try {
Assert.assertEquals("INSTALLED", Bundle.INSTALLED, hostBundle.getState());
input = deployer.getDeployment(BUNDLE_H_FRAG_JAR);
Bundle fragBundle = context.installBundle(BUNDLE_H_FRAG_JAR, input);
try {
Assert.assertEquals("INSTALLED", Bundle.INSTALLED, fragBundle.getState());
hostBundle.start();
Assert.assertEquals("ACTIVE", Bundle.ACTIVE, hostBundle.getState());
String result = performCall("/bundle-g/servlet?input=Hello");
Assert.assertEquals("Simple Servlet called with input=Hello", result);
result = performCall("/bundle-g/message.txt");
Assert.assertEquals("Hello from Resource", result);
result = performCall("/bundle-g/message-frag.txt");
Assert.assertEquals("Hello from Fragment Resource", result);
} finally {
deployer.undeploy(BUNDLE_H_FRAG_JAR);
}
} finally {
deployer.undeploy(BUNDLE_G_HOST_JAR);
}
}

@Test
public void testDeferredBundleWithWabExtension() throws Exception {
InputStream input = deployer.getDeployment(BUNDLE_C_WAB);
Expand Down Expand Up @@ -393,4 +472,43 @@ public InputStream openStream() {
});
return archive;
}

@Deployment(name = BUNDLE_G_HOST_JAR, managed = false, testable = false)
public static Archive<?> getBundleG() {
final JavaArchive archive = ShrinkWrap.create(JavaArchive.class, BUNDLE_G_HOST_JAR);
archive.addClasses(SimpleServlet.class, Echo.class);
archive.addAsResource(STRING_ASSET, "message.txt");
archive.setManifest(new Asset() {
@Override
public InputStream openStream() {
OSGiManifestBuilder builder = OSGiManifestBuilder.newInstance();
builder.addBundleSymbolicName(archive.getName());
builder.addBundleManifestVersion(2);
builder.addImportPackages(PostConstruct.class, WebServlet.class);
builder.addImportPackages(Servlet.class, HttpServlet.class);
builder.addManifestHeader("Web-ContextPath", "/bundle-g");
builder.addRequiredCapabilities("fragment-h");
return builder.openStream();
}
});
return archive;
}

@Deployment(name = BUNDLE_H_FRAG_JAR, managed = false, testable = false)
public static Archive<?> getBundleH() {
final JavaArchive archive = ShrinkWrap.create(JavaArchive.class, BUNDLE_H_FRAG_JAR);
archive.addAsResource(STRING_FRAG_ASSET, "message-frag.txt");
archive.setManifest(new Asset() {
@Override
public InputStream openStream() {
OSGiManifestBuilder builder = OSGiManifestBuilder.newInstance();
builder.addBundleSymbolicName(archive.getName());
builder.addBundleManifestVersion(2);
builder.addFragmentHost(BUNDLE_G_HOST_JAR);
builder.addProvidedCapabilities("fragment-h");
return builder.openStream();
}
});
return archive;
}
}
Expand Up @@ -153,6 +153,11 @@ public void testWebXMLInFragment() throws Exception {
Bundle bundle = FrameworkUtils.getBundles(context, BUNDLE_C_WAB, null)[0];
Enumeration<URL> entries = bundle.findEntries("WEB-INF", "web.xml", true);
Assert.assertNotNull("WEb-INF/web.xml entries found", entries);
// JBOSGI-794
result = performCall("/bundleC/host-message.txt");
Assert.assertEquals("Hello from Host", result);
result = performCall("/bundleC/fragment-message.txt");
Assert.assertEquals("Hello from Fragment", result);
} finally {
deployer.undeploy(BUNDLE_C_WAB);
deployer.undeploy(FRAGMENT_C);
Expand Down
Expand Up @@ -23,6 +23,12 @@

import java.io.IOException;
import java.net.URL;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.xml.stream.XMLInputFactory;
import javax.xml.stream.XMLStreamException;
Expand All @@ -31,10 +37,12 @@
import org.jboss.as.ee.structure.SpecDescriptorPropertyReplacement;
import org.jboss.as.osgi.OSGiConstants;
import org.jboss.as.osgi.OSGiLogger;
import org.jboss.as.server.deployment.Attachments;
import org.jboss.as.server.deployment.DeploymentPhaseContext;
import org.jboss.as.server.deployment.DeploymentUnit;
import org.jboss.as.server.deployment.DeploymentUnitProcessingException;
import org.jboss.as.server.deployment.DeploymentUnitProcessor;
import org.jboss.as.server.deployment.module.ResourceRoot;
import org.jboss.as.web.common.WarMetaData;
import org.jboss.metadata.merge.web.jboss.JBossWebMetaDataMerger;
import org.jboss.metadata.parser.servlet.WebMetaDataParser;
Expand All @@ -43,6 +51,7 @@
import org.jboss.metadata.web.spec.WebMetaData;
import org.jboss.osgi.resolver.XBundle;
import org.jboss.osgi.resolver.XBundleRevision;
import org.jboss.vfs.VirtualFile;
import org.osgi.framework.namespace.HostNamespace;
import org.osgi.framework.wiring.BundleWire;
import org.osgi.framework.wiring.BundleWiring;
Expand All @@ -55,58 +64,87 @@
*/
public class WebBundleFragmentProcessor implements DeploymentUnitProcessor {

private final Map<XBundleRevision, VirtualFile> fragmentRoots = new HashMap<>();

@Override
public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentUnitProcessingException {
DeploymentUnit depUnit = phaseContext.getDeploymentUnit();
XBundleRevision hostRev = depUnit.getAttachment(OSGiConstants.BUNDLE_REVISION_KEY);
WarMetaData warMetaData = depUnit.getAttachment(WarMetaData.ATTACHMENT_KEY);

if (hostRev != null && hostRev.isFragment()) {
ResourceRoot resourceRoot = depUnit.getAttachment(Attachments.DEPLOYMENT_ROOT);
if (resourceRoot != null) {
synchronized (fragmentRoots) {
fragmentRoots.put(hostRev, resourceRoot.getRoot());
}
}
}

if (warMetaData == null || hostRev == null)
return;

XBundle fragment = null;
List<XBundle> fragments = new ArrayList<XBundle>();

// Get attached fragments
BundleWiring wiring = hostRev.getWiring();
for (BundleWire wire : wiring.getProvidedWires(HostNamespace.HOST_NAMESPACE)) {
fragment = (XBundle) wire.getRequirer().getBundle();
fragments.add((XBundle) wire.getRequirer().getBundle());
break;
}

// No attached fragments
if (fragment == null)
if (fragments.size() == 0)
return;

// Check if the fragment has a web.xml entry
// Check if the first fragment has a web.xml entry
XBundle fragment = fragments.get(0);
URL entry = fragment.getEntry("WEB-INF/web.xml");
if (entry == null)
return;

// Parse the web.xml
WebMetaData fragmentMetaData = null;
try {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
MetaDataElementParser.DTDInfo dtdInfo = new MetaDataElementParser.DTDInfo();
inputFactory.setXMLResolver(dtdInfo);
XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(entry.openStream());
fragmentMetaData = WebMetaDataParser.parse(xmlReader, dtdInfo, SpecDescriptorPropertyReplacement.propertyReplacer(depUnit));
} catch (XMLStreamException ex) {
OSGiLogger.LOGGER.debugf(ex, "Cannot parse web.xml in fragment: %s", fragment);
} catch (IOException ex) {
OSGiLogger.LOGGER.debugf(ex, "Cannot parse web.xml in fragment: %s", fragment);
if (entry != null) {
// Parse the web.xml
WebMetaData fragmentMetaData = null;
try {
XMLInputFactory inputFactory = XMLInputFactory.newInstance();
MetaDataElementParser.DTDInfo dtdInfo = new MetaDataElementParser.DTDInfo();
inputFactory.setXMLResolver(dtdInfo);
XMLStreamReader xmlReader = inputFactory.createXMLStreamReader(entry.openStream());
fragmentMetaData = WebMetaDataParser.parse(xmlReader, dtdInfo, SpecDescriptorPropertyReplacement.propertyReplacer(depUnit));
} catch (XMLStreamException ex) {
OSGiLogger.LOGGER.errorf(ex, "Cannot parse web.xml in fragment: %s", fragment);
} catch (IOException ex) {
OSGiLogger.LOGGER.errorf(ex, "Cannot parse web.xml in fragment: %s", fragment);
}
// Merge additional {@link WebMetaData}
if (fragmentMetaData != null) {
warMetaData.setWebMetaData(fragmentMetaData);
JBossWebMetaData mergedMetaData = new JBossWebMetaData();
JBossWebMetaData metaData = warMetaData.getMergedJBossWebMetaData();
JBossWebMetaDataMerger.merge(mergedMetaData, metaData, fragmentMetaData);
warMetaData.setMergedJBossWebMetaData(mergedMetaData);
}
}

// Merge additional {@link WebMetaData}
if (fragmentMetaData != null) {
warMetaData.setWebMetaData(fragmentMetaData);
JBossWebMetaData mergedMetaData = new JBossWebMetaData();
JBossWebMetaData metaData = warMetaData.getMergedJBossWebMetaData();
JBossWebMetaDataMerger.merge(mergedMetaData, metaData, fragmentMetaData);
warMetaData.setMergedJBossWebMetaData(mergedMetaData);
Set<VirtualFile> overlays = new LinkedHashSet<>();
synchronized (fragmentRoots) {
for (XBundle frag : fragments) {
VirtualFile fragRoot = fragmentRoots.get(frag.getBundleRevision());
if (fragRoot != null) {
overlays.add(fragRoot);
}
}
}
if (overlays.size() > 0) {
warMetaData.setOverlays(overlays);
}
}

@Override
public void undeploy(final DeploymentUnit depUnit) {
// do nothing
XBundleRevision hostRev = depUnit.getAttachment(OSGiConstants.BUNDLE_REVISION_KEY);
if (hostRev != null && hostRev.isFragment()) {
synchronized (fragmentRoots) {
fragmentRoots.remove(hostRev);
}
}
}
}
Expand Up @@ -84,9 +84,8 @@ public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentU

// Check for attached BundleInfo
BundleInfo info = depUnit.getAttachment(OSGiConstants.BUNDLE_INFO_KEY);
OSGiMetaData metadata = null;
if (info != null) {
metadata = info.getOSGiMetadata();
OSGiMetaData metadata = info.getOSGiMetadata();

if (deployment == null) {
deployment = DeploymentFactory.createDeployment(info);
Expand Down Expand Up @@ -158,8 +157,9 @@ public void deploy(final DeploymentPhaseContext phaseContext) throws DeploymentU
}
excludedSubsystems.addAll(Arrays.asList(EXCLUDED_SUBSYSTEMS));

OSGiMetaData metadata = depUnit.getAttachment(OSGiConstants.OSGI_METADATA_KEY);
if (metadata != null && metadata.isFragment()) {
// JBOSGI-751, JBOSGI-761, JBOSGI-793
// JBOSGI-751, JBOSGI-761, JBOSGI-793, JBOSGI-794
excludedSubsystems.add("webservices");
excludedSubsystems.add("ee");
}
Expand Down