I have an issue with #RepositoryRestResource returning a 500 error due to a null pointer.
I have an abstract class named Resource which is uses InheritanceType.JOINED and #JsonSubTypes to provide about 5 subclasses of Resource such as ServerResource. The specific Resource is returned fine when referenced in another entity that it joins with. The PagingAndSortingRepository also works fine when called in code. The problem is the endpoint exposed by #RepositoryRestResource for the Resource entity returns a 500 error (due to NPE) when called directly.
After debugging, I found the issue is due to the line PersistentEntityResourceAssembler:154. The mapping object is null because the framework could not map ServerResource.class to the parent Resource.class. The cache is a map, and uses .getClass().
Are there any ways I can get one endpoint for the Resource entity working for these separate types? This almost seems like a bug.
To correct this issue i overrode the resourceMappings() method, and injected the mappings I needed. This fixed the issue, and now the /resources uri is working as intended.
package com.environment.config;
import java.lang.reflect.Field;
import java.util.Map;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.type.filter.AssignableTypeFilter;
import org.springframework.data.rest.core.config.RepositoryRestConfiguration;
import org.springframework.data.rest.core.mapping.RepositoryResourceMappings;
import org.springframework.data.rest.core.mapping.ResourceMappings;
import org.springframework.data.rest.core.mapping.ResourceMetadata;
import org.springframework.data.rest.webmvc.config.RepositoryRestMvcConfiguration;
import com.environment.domain.Resource;
import com.environment.util.Tuple;
#Configuration
public class RepositoryConfig extends RepositoryRestMvcConfiguration {
#Override
public ResourceMappings resourceMappings() {
RepositoryResourceMappings rm = RepositoryResourceMappings)super.resourceMappings();
try {
Field cacheField = rm.getClass().getDeclaredField("cache");
cacheField.setAccessible(true);
Map<Class<?>, ResourceMetadata> cache = (Map<Class<?>, ResourceMetadata>) cacheField.get(rm);
//Get metadata for parent object
ResourceMetadata resourceMetadata = cache.entrySet().stream()
.map(Tuple<Class<?>,ResourceMetadata>::new)
.filter(t -> Resource.class.equals(t.t))
.map(t -> t.u)
.findFirst()
.get();
ClassPathScanningCandidateComponentProvider provider = new ClassPathScanningCandidateComponentProvider(false);
provider.addIncludeFilter(new AssignableTypeFilter(Resource.class));
provider.findCandidateComponents("com/environment")
.stream()
.map(beanDef -> {
try {
return Class.forName(beanDef.getBeanClassName());
} catch (Exception e) {
e.printStackTrace();
}
return null;
})
.filter(c -> !Resource.class.equals(c))
.filter(c -> Resource.class.isAssignableFrom(c))
.peek(c -> System.out.println("Mapping: " + c)
.forEach(c -> cache.put((Class<?>) c, resourceMetadata));
} catch (Exception e) {
e.printStackTrace();
}
return rm;
}
}
Related
One operator deleted Data Dictionary and restarted Alfresco 3.4.12 Enterprise Edition. The context /alfresco doesn't start with the following exception:
17:43:11,100 INFO [STDOUT] 17:43:11,097 ERROR [web.context.ContextLoader] Context initialization failed
org.alfresco.error.AlfrescoRuntimeException: 08050000 Failed to find 'app:dictionary' node
at org.alfresco.repo.action.scheduled.ScheduledPersistedActionServiceImpl.locatePersistanceFolder(ScheduledPersistedActionServiceImpl.java:132)
Looking at the source code in org.alfresco.repo.action.scheduled.ScheduledPersistedActionServiceImpl.java, the path is hardwired.
Then we followed the tip from https://community.alfresco.com/thread/202859-error-failed-to-find-appdictionary-node, editing bootstrap-context.xml, comment out the class.
After the change the error went over, now the RenditionService couldn't start.
We're looking for a way to recover the deleted node, since we can obtain the nodeid from the database. So we created a small class and invoke it through spring in bootstrap-context.xml, but it's failing due to permissions. Could you take a look at the code and tell us what's wrong. The code is:
package com.impulseit.test;
import javax.transaction.UserTransaction;
import org.alfresco.repo.node.archive.NodeArchiveService;
import org.alfresco.repo.node.archive.RestoreNodeReport;
import org.alfresco.repo.security.authentication.AuthenticationUtil;
import org.alfresco.repo.security.authentication.AuthenticationUtil.RunAsWork;
import org.alfresco.service.ServiceRegistry;
import org.alfresco.service.cmr.repository.NodeRef;
public class RestoreNode {
private NodeArchiveService nodeArchiveService;
private ServiceRegistry serviceRegistry;
private String nodeName ="archive://SpacesStore/adfc0cfe-e20b-467f-ad71-253aea8f9ac9";
public void setNodeArchiveService(NodeArchiveService value)
{
this.nodeArchiveService = value;
}
public void setServiceRegistry(ServiceRegistry value)
{
this.serviceRegistry = value;
}
public void doRestore() {
RunAsWork<Void> runAsWork = new RunAsWork<Void>()
{
public Void doWork() throws Exception
{
NodeRef nodeRef = new NodeRef(nodeName);
//RestoreNodeReport restoreNodeReport =
UserTransaction trx_A = serviceRegistry.getTransactionService().getUserTransaction();
trx_A.begin();
AuthenticationUtil.setFullyAuthenticatedUser(AuthenticationUtil.getSystemUserName());
RestoreNodeReport restored = nodeArchiveService.restoreArchivedNode(nodeRef);
trx_A.commit();
return null;
}
};
AuthenticationUtil.runAs(runAsWork,AuthenticationUtil.getSystemUserName());
}
public RestoreNode() {
}
}
The exception is:
19:31:21,747 User:admin ERROR [node.archive.NodeArchiveServiceImpl] An unhandled exception stopped the restore
java.lang.NullPointerException
at org.alfresco.repo.security.permissions.impl.model.PermissionModel.getPermissionReference(PermissionModel.java:1315)
at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.getPermissionReference(PermissionServiceImpl.java:956)
at org.alfresco.repo.security.permissions.impl.PermissionServiceImpl.hasPermission(PermissionServiceImpl.java:976)
Thank you in advance.
Luis
First, I am a beginner in java servlets, maven projects and apis.
I am doing the following tutorial on getting started with google endpoints, which is a tutorial implementing the following maven project source code on github. On the web.xml, there is only one named Servlet, the EndpointsServlet like so:
<!-- wrap the backend with Endpoints Framework v2. -->
<servlet>
<servlet-name>EndpointsServlet</servlet-name>
<servlet-class>com.google.api.server.spi.EndpointsServlet</servlet-class>
<init-param>
<param-name>services</param-name>
<param-value>com.example.echo.Echo</param-value>
</init-param>
</servlet>
What I dont understand is why are there no other servlets on the project? There are only 3 java classes in the main directory and none of them are servlet files. I am assuming that this project is a sample api with server side logic (such as routing and responding to requests) like any other servlet project which means there should be more than this servlet.
The comment on the web.xml is an obvious clue as to what it does but I dont really know what wrapping the backend with endpoints framework means. Also, I actually got the EndpointsServlet.java file and it says the servlet is a "handler for proxy-less API serving. This servlet understands and replies in JSON-REST. Again, I dont really understand this comment nor what the servlet does even reading it. Servlet code below:
package com.google.api.server.spi;
import com.google.api.server.spi.SystemService.EndpointNode;
import com.google.api.server.spi.config.ApiConfigException;
import com.google.api.server.spi.config.model.ApiClassConfig.MethodConfigMap;
import com.google.api.server.spi.config.model.ApiConfig;
import com.google.api.server.spi.config.model.ApiMethodConfig;
import com.google.api.server.spi.dispatcher.PathDispatcher;
import com.google.api.server.spi.handlers.ApiProxyHandler;
import com.google.api.server.spi.handlers.CorsHandler;
import com.google.api.server.spi.handlers.EndpointsMethodHandler;
import com.google.api.server.spi.handlers.ExplorerHandler;
import com.google.common.collect.ImmutableList;
import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map.Entry;
import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* A handler for proxy-less API serving. This servlet understands and replies in JSON-REST.
*/
public class EndpointsServlet extends HttpServlet {
private static final String EXPLORER_PATH = "explorer";
private ServletInitializationParameters initParameters;
private SystemService systemService;
private PathDispatcher<EndpointsContext> dispatcher;
private CorsHandler corsHandler;
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
ClassLoader classLoader = getClass().getClassLoader();
this.initParameters = ServletInitializationParameters.fromServletConfig(config, classLoader);
this.systemService = createSystemService(classLoader, initParameters);
this.dispatcher = createDispatcher();
this.corsHandler = new CorsHandler();
}
#Override
public void service(HttpServletRequest request, HttpServletResponse response) throws IOException {
String method = getRequestMethod(request);
if ("OPTIONS".equals(method)) {
corsHandler.handle(request, response);
} else {
String path = Strings.stripSlash(
request.getRequestURI().substring(request.getServletPath().length()));
EndpointsContext context = new EndpointsContext(method, path, request, response,
initParameters.isPrettyPrintEnabled());
if (!dispatcher.dispatch(method, path, context)) {
response.setStatus(HttpServletResponse.SC_NOT_FOUND);
response.getWriter().append("Not Found");
}
}
}
private String getRequestMethod(HttpServletRequest request) {
Enumeration headerNames = request.getHeaderNames();
String methodOverride = null;
while (headerNames.hasMoreElements()) {
String headerName = (String) headerNames.nextElement();
if (headerName.toLowerCase().equals("x-http-method-override")) {
methodOverride = request.getHeader(headerName);
break;
}
}
return methodOverride != null ? methodOverride.toUpperCase() : request.getMethod();
}
private PathDispatcher<EndpointsContext> createDispatcher() {
PathDispatcher.Builder<EndpointsContext> builder = PathDispatcher.builder();
List<EndpointNode> endpoints = systemService.getEndpoints();
// We're building an ImmutableList here, because it will eventually be used for JSON-RPC.
ImmutableList.Builder<EndpointsMethodHandler> handlersBuilder = ImmutableList.builder();
for (EndpointNode endpoint : endpoints) {
ApiConfig apiConfig = endpoint.getConfig();
MethodConfigMap methods = apiConfig.getApiClassConfig().getMethods();
for (Entry<EndpointMethod, ApiMethodConfig> methodEntry : methods.entrySet()) {
if (!methodEntry.getValue().isIgnored()) {
handlersBuilder.add(
new EndpointsMethodHandler(initParameters, getServletContext(), methodEntry.getKey(),
apiConfig, methodEntry.getValue(), systemService));
}
}
}
ImmutableList<EndpointsMethodHandler> handlers = handlersBuilder.build();
for (EndpointsMethodHandler handler : handlers) {
builder.add(handler.getRestMethod(), Strings.stripTrailingSlash(handler.getRestPath()),
handler.getRestHandler());
}
ExplorerHandler explorerHandler = new ExplorerHandler();
builder.add("GET", EXPLORER_PATH, explorerHandler);
builder.add("GET", EXPLORER_PATH + "/", explorerHandler);
builder.add("GET", "static/proxy.html", new ApiProxyHandler());
return builder.build();
}
private SystemService createSystemService(ClassLoader classLoader,
ServletInitializationParameters initParameters) throws ServletException {
try {
SystemService.Builder builder = SystemService.builder()
.withDefaults(classLoader)
.setStandardConfigLoader(classLoader)
.setIllegalArgumentIsBackendError(initParameters.isIllegalArgumentBackendError())
.setDiscoveryServiceEnabled(true);
for (Class<?> serviceClass : initParameters.getServiceClasses()) {
builder.addService(serviceClass, createService(serviceClass));
}
return builder.build();
} catch (ApiConfigException | ClassNotFoundException e) {
throw new ServletException(e);
}
}
/**
* Creates a new instance of the specified service class.
*
* #param serviceClass the class of the service to create
*/
protected <T> T createService(Class<T> serviceClass) {
try {
return serviceClass.newInstance();
} catch (InstantiationException e) {
throw new RuntimeException(
String.format("Cannot instantiate service class: %s", serviceClass.getName()), e);
} catch (IllegalAccessException e) {
throw new RuntimeException(
String.format("Cannot access service class: %s", serviceClass.getName()), e);
}
}
}
EndpointsServlet handles all API calls with a certain path prefix. It takes a RESTful API call and translates it into POJO(s) and dispatches it to a Java method you've written, and then serializes the return value of that method to JSON. It does this based on how you annotate your code.
I am working on a project where I need access method arguments during execution.
Is it possible to print method arguments using byte buddy framework? any sample code on this using javaagent is highly appreciated.
Yes, this is possible. You can use MethodDelegation or Advice to inject your code and then use the #AllArguments annotation to get hold of the actual arguments.
The question is, how do you create your code in your project? You can either use a Java agent with the AgentBuilder or create proxy subclasses using ByteBuddy instances. Refer to the documentation and the mentioned classes javadoc to find out how this is done.
Here is an example of how this can be implemented using MethodDelegation. I use it to measure the execution time of methods. I specifically did not begin to remove the extra code, because I want to more fully reveal the capabilities of Byte Buddy.
package md.leonis.shingler;
import net.bytebuddy.agent.ByteBuddyAgent;
import net.bytebuddy.agent.builder.AgentBuilder;
import net.bytebuddy.implementation.MethodDelegation;
import net.bytebuddy.implementation.bind.annotation.AllArguments;
import net.bytebuddy.implementation.bind.annotation.Origin;
import net.bytebuddy.implementation.bind.annotation.RuntimeType;
import net.bytebuddy.implementation.bind.annotation.SuperCall;
import net.bytebuddy.matcher.ElementMatchers;
import java.lang.instrument.Instrumentation;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.concurrent.Callable;
import java.util.stream.Collectors;
public class MeasureMethodTest {
public static void main(String[] args) throws InterruptedException {
premain(ByteBuddyAgent.install());
for (int i = 0; i < 4; i++) {
SampleClass.foo("arg" + i);
}
}
public static void premain(Instrumentation instrumentation) {
new AgentBuilder.Default()
.type(ElementMatchers.nameStartsWith("md.leonis.shingler"))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class))
).installOn(instrumentation);
}
public static class AccessInterceptor {
#RuntimeType
public static Object intercept(#Origin Method method, #SuperCall Callable<?> callable, #AllArguments Object[] args) throws Exception {
long start = System.nanoTime();
try {
return callable.call();
} finally {
if (method.getAnnotationsByType(Measured.class).length > 0) {
String params = Arrays.stream(args).map(Object::toString).collect(Collectors.joining(", "));
System.out.println(method.getReturnType().getSimpleName() + " " + method.getName() + "("+ params +") took " + ((System.nanoTime() - start) / 1000000) + " ms");
}
}
}
}
public static class SampleClass {
#Measured
static void foo(String s) throws InterruptedException {
Thread.sleep(50);
}
}
}
This example measures the execution time of all methods found in the md.leonis.shingler package and marked with the #Measured annotation.
To run it, you need two libraries: byte-buddy and byte-buddy-agent.
The result of work:
void foo(arg0) took 95 ms
void foo(arg1) took 50 ms
void foo(arg2) took 50 ms
void foo(arg3) took 50 ms
Note that the console displays the values of all arguments passed to the method. This is the answer to the question asked.
Here is the annotation example:
package md.leonis.shingler;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.METHOD)
public #interface Measured {
}
To be honest, I was not able to directly configure filtering by annotations in the Agent. Here is an example (not working):
new AgentBuilder.Default()
.type(ElementMatchers.isAnnotatedWith(Measured.class))
.transform((builder, type, classLoader, module) ->
builder.method(ElementMatchers.any()).intercept(MethodDelegation.to(AccessInterceptor.class))
).installOn(instrumentation);
If someone knows how to do this, please comment below.
I am trying to run the following program.I am using glassfish server 3.1.2 to enable this MDB to run.Then too I am unanble to run it.
package com.mdb;
import javax.jms.ConnectionFactory;
import javax.jms.Queue;
import javax.jms.Connection;
import javax.jms.Session;
import javax.jms.QueueBrowser;
import javax.jms.Message;
import javax.jms.JMSException;
import javax.annotation.Resource;
import java.util.Enumeration;
import javax.ejb.Stateless;
/**
* The MessageBrowser class inspects a queue and displays the messages it
* holds.
*/
#Stateless
public class MessageClient {
#Resource(mappedName = "jms/ConnectionFactory")
private static ConnectionFactory connectionFactory;
#Resource(mappedName = "jms/Queue")
private static Queue queue;
/**
* Main method.
*
* #param args the queue used by the example
*/
public static void main(String[] args) {
Connection connection = null;
try {
System.out.println("1");
connection = connectionFactory.createConnection();
System.out.println("2");
Session session = connection.createSession(
false,
Session.AUTO_ACKNOWLEDGE);
QueueBrowser browser = session.createBrowser(queue);
Enumeration msgs = browser.getEnumeration();
if (!msgs.hasMoreElements()) {
System.out.println("No messages in queue");
} else {
while (msgs.hasMoreElements()) {
Message tempMsg = (Message) msgs.nextElement();
System.out.println("Message: " + tempMsg);
}
}
} catch (JMSException e) {
System.err.println("Exception occurred: " + e.toString());
} finally {
if (connection != null) {
try {
connection.close();
} catch (JMSException e) {
}
}
}
}
}
The problem is I get the follwing exsception upon runing it.
Exception in thread "main" java.lang.NullPointerException
at com.mdb.MessageClient.main(MessageClient.java:35)
What may be the problem here?
What you have build is not a MDB. It's a stateless session bean that browses a queue.
A MDB has the #MessageDriven annotation. It's invoked whenever a message comes in.
Apart from that, you might want to use the "lookup" attribute instead of the "mappedName" one. The latter is from an ancient time when people weren't sure yet about anything, and needed a temporary hack to make things magically work.
Your usage of static fields and the static main method inside a stateless bean make no sense at all. If you're accessing your bean via that main method you're not using the bean at all and you're just calling an isolated global-like method. If anything, this might be the source of your NPE.
The fix isn't really simple. You're seemingly completely confused between Java EE and Java SE, and between instances and static methods.
I would like to use a custom realm with glassfish 3.1
I took the two file from this topic to try. Custom Glassfish Security Realm does not work (unable to find LoginModule)
The CustomRealm.java
package com.company.security.realm;
import com.sun.appserv.security.AppservRealm;
import com.sun.enterprise.security.auth.realm.BadRealmException;
import com.sun.enterprise.security.auth.realm.InvalidOperationException;
import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.NoSuchUserException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;
public class CustomRealm extends AppservRealm
{
Vector<String> groups = new Vector<String>();
private String jaasCtxName;
private String startWith;
#Override
public void init(Properties properties)
throws BadRealmException, NoSuchRealmException {
jaasCtxName = properties.getProperty("jaas-context", "customRealm");
startWith = properties.getProperty("startWith", "z");
groups.add("dummy");
}
#Override
public String getAuthType()
{
return "Custom Realm";
}
public String[] authenticate(String username, char[] password)
{
// if (isValidLogin(username, password))
return (String[]) groups.toArray();
}
#Override
public Enumeration getGroupNames(String username)
throws InvalidOperationException, NoSuchUserException
{
return groups.elements();
}
#Override
public String getJAASContext()
{
return jaasCtxName;
}
public String getStartWith()
{
return startWith;
}
}
And the custom login module
package com.company.security.realm;
import com.sun.appserv.security.AppservPasswordLoginModule;
import com.sun.enterprise.security.auth.login.common.LoginException;
import java.util.Set;
import org.glassfish.security.common.PrincipalImpl;
public class CustomLoginModule extends AppservPasswordLoginModule
{
#Override
protected void authenticateUser() throws LoginException
{
_logger.info("CustomRealm : authenticateUser for " + _username);
final CustomRealm realm = (CustomRealm)_currentRealm;
if ( (_username == null) || (_username.length() == 0) || !_username.startsWith(realm.getStartWith()))
throw new LoginException("Invalid credentials");
String[] grpList = realm.authenticate(_username, getPasswordChar());
if (grpList == null) {
throw new LoginException("User not in groups");
}
_logger.info("CustomRealm : authenticateUser for " + _username);
Set principals = _subject.getPrincipals();
principals.add(new PrincipalImpl(_username));
this.commitUserAuthentication(grpList);
}
}
I added as well the module to the conf file
customRealm {
com.company.security.realm.CustomLoginModule required;
};
And I copy my 2 .class in the glassfish3/glassfish/domains/domain1/lib/classes/
as well as glassfish3/glassfish/lib
Everytime I want to create a new realm I have got the same error.
./asadmin --port 4949 create-auth-realm --classname com.company.security.realm.CustomRealm --property jaas-context=customRealm:startWith=a customRealm
remote failure: Creation of Authrealm customRealm failed. com.sun.enterprise.security.auth.realm.BadRealmException: java.lang.ClassNotFoundException: com.company.security.realm.CustomRealm not found by org.glassfish.security [101]
com.sun.enterprise.security.auth.realm.BadRealmException: java.lang.ClassNotFoundException: com.company.security.realm.CustomRealm not found by org.glassfish.security [101]
Command create-auth-realm failed.
I think i dont really understand how to add in the proper way my two files to glassfish.
This two files are created and compile from eclipse. I create a java project suctom login.
Someone can help ?
Thx a lot in advance,
loic
Did you package it as an OSGi module (see the answer in the post you referenced)? If so, don't copy the jar file into $GF_HOME/lib or anything, instead deploy it as an OSGi module:
asadmin deploy --type osgi /path/to/CustomRealm.jar
Then add the login.conf settings. To be on the safe side, I'd restart GF (asadmin restart-domain), then you can create the realm with the command you have there.