Skip to content

Commit

Permalink
WELD-1430 Use optimized session keys if possible
Browse files Browse the repository at this point in the history
  • Loading branch information
mkouba authored and jharting committed Mar 6, 2014
1 parent 5f22373 commit 9aa7342
Show file tree
Hide file tree
Showing 5 changed files with 245 additions and 8 deletions.
28 changes: 26 additions & 2 deletions impl/src/main/java/org/jboss/weld/bootstrap/WeldStartup.java
Expand Up @@ -118,6 +118,7 @@
import org.jboss.weld.resources.spi.ClassFileServices;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.resources.spi.ScheduledExecutorServiceFactory;
import org.jboss.weld.serialization.BeanIdentifierIndex;
import org.jboss.weld.serialization.ContextualStoreImpl;
import org.jboss.weld.serialization.spi.ContextualStore;
import org.jboss.weld.serialization.spi.ProxyServices;
Expand Down Expand Up @@ -256,6 +257,7 @@ private void addImplementationServices(ServiceRegistry services) {
services.add(CurrentEventMetadata.class, new CurrentEventMetadata());
services.add(SpecializationAndEnablementRegistry.class, new SpecializationAndEnablementRegistry());
services.add(MissingDependenciesRegistry.class, new MissingDependenciesRegistry());
services.add(BeanIdentifierIndex.class, new BeanIdentifierIndex());

GlobalObserverNotifierService observerNotificationService = new GlobalObserverNotifierService(services, contextId);
services.add(GlobalObserverNotifierService.class, observerNotificationService);
Expand Down Expand Up @@ -413,6 +415,10 @@ public void validateBeans() {
}

public void endInitialization() {

// Build a special index of bean identifiers
deploymentManager.getServices().get(BeanIdentifierIndex.class).build(getBeansForBeanIdentifierIndex());

// TODO rebuild the manager accessibility graph if the bdas have changed
// Register the managers so external requests can handle them
// clear the TypeSafeResolvers, so data that is only used at startup
Expand Down Expand Up @@ -485,8 +491,8 @@ protected Collection<ContextHolder<? extends Context>> createContexts(ServiceReg

if (Reflections.isClassLoadable(ServletApiAbstraction.SERVLET_CONTEXT_CLASS_NAME, WeldClassLoaderResourceLoader.INSTANCE)) {
// Register the Http contexts if not in
contexts.add(new ContextHolder<HttpSessionContext>(new HttpSessionContextImpl(contextId), HttpSessionContext.class, HttpLiteral.INSTANCE));
contexts.add(new ContextHolder<HttpSessionDestructionContext>(new HttpSessionDestructionContext(contextId), HttpSessionDestructionContext.class, HttpLiteral.INSTANCE));
contexts.add(new ContextHolder<HttpSessionContext>(new HttpSessionContextImpl(contextId, services.get(BeanIdentifierIndex.class)), HttpSessionContext.class, HttpLiteral.INSTANCE));
contexts.add(new ContextHolder<HttpSessionDestructionContext>(new HttpSessionDestructionContext(contextId, services.get(BeanIdentifierIndex.class)), HttpSessionDestructionContext.class, HttpLiteral.INSTANCE));
contexts.add(new ContextHolder<HttpConversationContext>(new LazyHttpConversationContextImpl(contextId), HttpConversationContext.class, HttpLiteral.INSTANCE));
contexts.add(new ContextHolder<HttpRequestContext>(new HttpRequestContextImpl(contextId), HttpRequestContext.class, HttpLiteral.INSTANCE));
}
Expand Down Expand Up @@ -529,4 +535,22 @@ public BeanManagerImpl getManager(BeanDeploymentArchive beanDeploymentArchive) {
BeanDeployment beanDeployment = bdaMapping.getBeanDeployment(beanDeploymentArchive);
return beanDeployment == null ? null : beanDeployment.getBeanManager().getCurrent();
}


/**
* Right now we only index all session scoped beans.
*
* @return the set of beans the index should be built from
*/
private Set<Bean<?>> getBeansForBeanIdentifierIndex() {
Set<Bean<?>> beans = new HashSet<Bean<?>>();
for (BeanDeployment beanDeployment : getBeanDeployments()) {
for (Bean<?> bean : beanDeployment.getBeanManager().getBeans()) {
if(bean.getScope().equals(SessionScoped.class)) {
beans.add(bean);
}
}
}
return beans;
}
}
@@ -0,0 +1,63 @@
/*
*
* JBoss, Home of Professional Open Source
* Copyright 2014, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.weld.context.beanstore;

import org.jboss.weld.bean.StringBeanIdentifier;
import org.jboss.weld.exceptions.IllegalStateException;
import org.jboss.weld.serialization.BeanIdentifierIndex;
import org.jboss.weld.serialization.spi.BeanIdentifier;

/**
* A naming scheme which makes use of {@link BeanIdentifierIndex} if possible.
*
* @author Martin Kouba
*/
public class BeanIdentifierIndexNamingScheme extends SimpleNamingScheme {

private static final String FALLBACK_FLAG = "F_";

private final BeanIdentifierIndex index;

public BeanIdentifierIndexNamingScheme(String prefix, BeanIdentifierIndex index) {
super(prefix);
this.index = index;
}

@Override
public BeanIdentifier deprefix(String id) {
String deprefixed = id.substring(getPrefix().length() + getDelimiter().length());
if (deprefixed.startsWith(FALLBACK_FLAG)) {
return new StringBeanIdentifier(deprefixed.substring(FALLBACK_FLAG.length()));
}
try {
return index.getIdentifier(Integer.valueOf(deprefixed));
} catch (NumberFormatException e) {
throw new IllegalStateException("Unable to deprefix invalid identifier", e);
}
}

@Override
public String prefix(BeanIdentifier id) {
Integer idx = index.getIndex(id);
if (idx == null) {
return getPrefix() + getDelimiter() + FALLBACK_FLAG + id.asString();
}
return getPrefix() + getDelimiter() + idx;
}

}
Expand Up @@ -9,21 +9,23 @@

import org.jboss.weld.Container;
import org.jboss.weld.context.AbstractBoundContext;
import org.jboss.weld.context.beanstore.BeanIdentifierIndexNamingScheme;
import org.jboss.weld.context.beanstore.NamingScheme;
import org.jboss.weld.context.beanstore.SimpleNamingScheme;
import org.jboss.weld.context.beanstore.http.EagerSessionBeanStore;
import org.jboss.weld.context.beanstore.http.LazySessionBeanStore;
import org.jboss.weld.serialization.BeanIdentifierIndex;

public class HttpSessionContextImpl extends AbstractBoundContext<HttpServletRequest> implements HttpSessionContext {

public static final SimpleNamingScheme NAMING_SCHEME = new SimpleNamingScheme(HttpSessionContext.class.getName());
// There is no need to store FQCN in a session key
static final String INDEX_NAMING_SCHEME_PREFIX = "WELD_S";

private final NamingScheme namingScheme;
private final String contextId;

public HttpSessionContextImpl(String contextId) {
public HttpSessionContextImpl(String contextId, BeanIdentifierIndex index) {
super(contextId, true);
this.namingScheme = NAMING_SCHEME;
this.namingScheme = new BeanIdentifierIndexNamingScheme(INDEX_NAMING_SCHEME_PREFIX, index);
this.contextId = contextId;
}

Expand Down
@@ -1,3 +1,19 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2013, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.weld.context.http;

import java.lang.annotation.Annotation;
Expand All @@ -6,7 +22,10 @@
import javax.servlet.http.HttpSession;

import org.jboss.weld.context.AbstractBoundContext;
import org.jboss.weld.context.beanstore.BeanIdentifierIndexNamingScheme;
import org.jboss.weld.context.beanstore.NamingScheme;
import org.jboss.weld.context.beanstore.http.EagerSessionBeanStore;
import org.jboss.weld.serialization.BeanIdentifierIndex;

/**
* This special http session context is necessary because HttpSessionListeners that are called when a session
Expand All @@ -18,16 +37,18 @@
*/
public class HttpSessionDestructionContext extends AbstractBoundContext<HttpSession> {

private final NamingScheme namingScheme;

public HttpSessionDestructionContext(String contextId) {
public HttpSessionDestructionContext(String contextId, BeanIdentifierIndex index) {
super(contextId, true);
this.namingScheme = new BeanIdentifierIndexNamingScheme(HttpSessionContextImpl.INDEX_NAMING_SCHEME_PREFIX, index);
}

@Override
public boolean associate(HttpSession session) {
if (getBeanStore() == null) {
// Don't reassociate
setBeanStore(new EagerSessionBeanStore(HttpSessionContextImpl.NAMING_SCHEME, session));
setBeanStore(new EagerSessionBeanStore(namingScheme, session));
return true;
} else {
return false;
Expand Down
@@ -0,0 +1,127 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2014, Red Hat, Inc., and individual contributors
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* Licensed 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.jboss.weld.serialization;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.PassivationCapable;

import org.jboss.weld.bean.CommonBean;
import org.jboss.weld.bean.StringBeanIdentifier;
import org.jboss.weld.bootstrap.api.Service;
import org.jboss.weld.exceptions.IllegalStateException;
import org.jboss.weld.serialization.spi.BeanIdentifier;
import org.jboss.weld.util.Preconditions;

import com.google.common.collect.ImmutableMap;

/**
* The index holds identifiers for the specified set of beans (note that only instances of {@link CommonBean} and implementations of {@link PassivationCapable}
* are included). Identifiers are sorted into ascending order, according to the {@link BeanIdentifier#asString()} natural ordering.
*
* @author Martin Kouba
*/
public class BeanIdentifierIndex implements Service {

private BeanIdentifier[] index;

private Map<BeanIdentifier, Integer> reverseIndex;

/**
*
* @param identifier
* @return the index value for the given identifier or null if the index does not contain the given identifier
*/
public Integer getIndex(BeanIdentifier identifier) {
checkIsBuilt();
Preconditions.checkArgumentNotNull(identifier, "identifier");
return reverseIndex.get(identifier);
}

/**
*
* @param idx
* @return the identifier for the given index
*/
public BeanIdentifier getIdentifier(int idx) {
checkIsBuilt();
return index[idx];
}

/**
* Note that the index can only be built once.
*
* @param beans The set of beans the index should be built from, only instances of {@link CommonBean} and implementations of {@link PassivationCapable} are
* included
* @throws IllegalStateException If the index is built already
*/
public void build(Set<Bean<?>> beans) {

if (index != null) {
throw new IllegalStateException("BeanIdentifier index is already built!");
}

if (beans.isEmpty()) {
index = new BeanIdentifier[0];
reverseIndex = Collections.emptyMap();
return;
}

List<BeanIdentifier> tempIndex = new ArrayList<BeanIdentifier>(beans.size());

for (Bean<?> bean : beans) {
if (bean instanceof CommonBean<?>) {
tempIndex.add(((CommonBean<?>) bean).getIdentifier());
} else if (bean instanceof PassivationCapable) {
tempIndex.add(new StringBeanIdentifier(((PassivationCapable) bean).getId()));
}
}

Collections.sort(tempIndex, new Comparator<BeanIdentifier>() {
@Override
public int compare(BeanIdentifier o1, BeanIdentifier o2) {
return o1.asString().compareTo(o2.asString());
}
});

index = tempIndex.toArray(new BeanIdentifier[tempIndex.size()]);

ImmutableMap.Builder<BeanIdentifier, Integer> builder = ImmutableMap.builder();
for (int i = 0; i < index.length; i++) {
builder.put(index[i], i);
}
reverseIndex = builder.build();
}

@Override
public void cleanup() {
index = null;
}

private void checkIsBuilt() {
if (index == null) {
throw new IllegalStateException("BeanIdentifier index not built!");
}
}

}

0 comments on commit 9aa7342

Please sign in to comment.