Glowroot and Axis

27 September 2018 Leave a comment

Unfortunately by default Glowroot does not support logging Axis’ service calls and their response time. You have to write a plugin for this, which is actually very easy once you grasp how the plugins work.

 

package org.glowroot.agent.plugin.axis.v.one;

import javax.xml.namespace.QName;

import org.glowroot.agent.plugin.api.Agent;
import org.glowroot.agent.plugin.api.MessageSupplier;
import org.glowroot.agent.plugin.api.ThreadContext;
import org.glowroot.agent.plugin.api.ThreadContext.Priority;
import org.glowroot.agent.plugin.api.Timer;
import org.glowroot.agent.plugin.api.TimerName;
import org.glowroot.agent.plugin.api.TraceEntry;
import org.glowroot.agent.plugin.api.checker.Nullable;
import org.glowroot.agent.plugin.api.weaving.BindReceiver;
import org.glowroot.agent.plugin.api.weaving.BindThrowable;
import org.glowroot.agent.plugin.api.weaving.BindTraveler;
import org.glowroot.agent.plugin.api.weaving.OnBefore;
import org.glowroot.agent.plugin.api.weaving.OnReturn;
import org.glowroot.agent.plugin.api.weaving.OnThrow;
import org.glowroot.agent.plugin.api.weaving.Pointcut;
import org.glowroot.agent.plugin.api.weaving.Shim;

public class AxisAspect {

  @Shim("org.apache.axis.client.Call")
  public interface Call {
    String getTargetEndpointAddress();
    QName getOperationName();
  }

  private static class TraceEntryOrTimer {

    private final @Nullable TraceEntry traceEntry;
    private final @Nullable Timer timer;

    private TraceEntryOrTimer(final TraceEntry traceEntry) {
      this.traceEntry = traceEntry;
      timer = null;
    }

    private TraceEntryOrTimer(final Timer timer) {
      this.timer = timer;
      traceEntry = null;
    }

    private void onReturn() {
      if (traceEntry != null) {
        traceEntry.end();
      } else if (timer != null) {
        timer.stop();
      }
    }

    private void onThrow(final Throwable t) {
      if (traceEntry != null) {
        traceEntry.endWithError(t);
      } else if (timer != null) {
        timer.stop();
      }
    }
  }

  @Pointcut(className = "org.apache.axis.client.Call", methodName = "invoke", methodParameterTypes = {}, timerName = "axis service")
  public static class ResourceAdvice {

    private static final TimerName timerName = Agent.getTimerName(ResourceAdvice.class);

    @OnBefore
    public static @Nullable TraceEntryOrTimer onBefore(final ThreadContext context, @BindReceiver final Call call) {
      String transactionName = call.getTargetEndpointAddress() + "#" + call.getOperationName().getLocalPart();
      context.setTransactionName(transactionName, Priority.CORE_PLUGIN);
      TraceEntry traceEntry = context.startServiceCallEntry("HTTP", transactionName, MessageSupplier.create("axis service: {}.{}()",
      call.getTargetEndpointAddress(), call.getOperationName().getLocalPart()), timerName);
      return new TraceEntryOrTimer(traceEntry);
    }

    @OnReturn
    public static void onReturn(@BindTraveler @Nullable final TraceEntryOrTimer entryOrTimer) {
      entryOrTimer.onReturn();
    }

    @OnThrow
    public static void onThrow(@BindThrowable final Throwable t, @BindTraveler @Nullable final TraceEntryOrTimer entryOrTimer) {
      entryOrTimer.onThrow(t);
    }
  }
}

 

 

and the corresponding glowroot.plugin.json

{
“name” : “Axis 1.4 Plugin”,
“id” : “axis”,
“aspects” : [“org.glowroot.agent.plugin.axis.v.one.AxisAspect”]
}

Categories: glowroot, Java Tags: ,

WTF again

30 November 2016 1 comment

Looking at legacy code, someone actually wrote a class that extends ArrayList

public class UserInterfaceModel extends ArrayList {

just because (s)he wanted to find out if a specific element was in the list!

public class UserInterfaceModel extends ArrayList {
    private static final long serialVersionUID = 1L;

    public UserInterfaceModel() {}

    public void addElement(UserInterfaceElement uie) {
        this.add(uie);
    }

    //chek if contains UserInterfaceElement in collection
    public boolean isContainingElement(String name) {
        for (int i=0;i<this.size();i++) {
            if (((UserInterfaceElement)this.get(i)).getName().equalsIgnoreCase(name)) {
                return true;
             }
         }
         return false;
    }
}

public class UserInterfaceElement {

    private String name;
    private String url;
...
}

Instead, the said programmer could just implement the equals method in the UserInterfaceElement element (to check only the name value) and just use a List.

Amzing, just amazing.

Categories: Java, WTF

[wsdlc] [ERROR] A class/interface with the same name “com.mydomain.layer.inbound.ws.ValidateResponse” is already in use. Use a class customizat ion to resolve this conflict.

6 February 2016 Leave a comment

I got the error [wsdlc] [ERROR] A class/interface with the same name "com.mydomain.layer.inbound.ws.ValidateResponse" is already in use. Use a class customization to resolve this conflict. a few days ago when I tried to generate the Java code from a WSDL file, using Oracle’s wsdlc Ant task. The problem is caused by having two elements with the same name, but with a different namespace, in the WSDL file. For example the following bit of code will result in the error above:

<s:element name="ValidateResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="ValidateResult" type="tns:ValidateResponse" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="ValidateResponse">
        <s:complexContent mixed="false">
          <s:extension base="tns:Response">
            <s:sequence>
              <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResponseStatus" />
              <s:element minOccurs="0" maxOccurs="1" name="SubscriptionExpiry" type="s:string" />
              <s:element minOccurs="0" maxOccurs="1" name="Allowed" type="tns:ArrayOfGuid" />
            </s:sequence>
          </s:extension>
        </s:complexContent>
      </s:complexType>

The solution to this is to use a JAXB Customisation Binding, as explained here. By using a JAXB Customisation Binding you can essentially bind a WSDL element to another type and therefore resolve the conflict, since in the generated Java code you end up with two different artifacts.

There are two ways do it. The first one is to use an external JAXB Customisation Binding file. Unfortunately this solution did not work for me. Not sure what the problem was. The second solution is to use inline JAXB Customisation Binding code. Fortunately this solution did work for me. By inlining the JAXB binding you end up with the following bit of code

      <s:element name="ValidateResponse">
        <s:complexType>
          <s:sequence>
            <s:element minOccurs="0" maxOccurs="1" name="ValidateResult" type="tns:ValidateResponse" />
          </s:sequence>
        </s:complexType>
      </s:element>
      <s:complexType name="ValidateResponse">
        <s:annotation>
          <s:appinfo>
            <jaxb:class name="ValidateResponseComplexType"/>
          </s:appinfo>
        </s:annotation>
      <s:complexContent mixed="false">
        <s:extension base="tns:Response">
          <s:sequence>
            <s:element minOccurs="1" maxOccurs="1" name="Status" type="tns:ResponseStatus" />
            <s:element minOccurs="0" maxOccurs="1" name="SubscriptionExpiry" type="s:string" />
            <s:element minOccurs="0" maxOccurs="1" name="Allowed" type="tns:ArrayOfGuid" />
          </s:sequence>
        </s:extension>
      </s:complexContent>
      </s:complexType>

When the wsdlc runs you will end up with the different classes for the ValidateResponse element: ValidateResponse and ValidateResponseComplexType. Of course you will also need to define the jaxb namespace: xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" in the WSDL file.

Categories: Java, Web Services Tags: ,

<BEA-000000> <java.lang.NegativeArraySizeException

17 December 2015 Leave a comment

If you get this error with WebLogic’s admin server

####<2015-12-17 14:30:14 EET> <Critical> <EmbeddedLDAP> <www.myserver.com> <AdminSOA> <VDE Replication Thread> <<anonymous>> <> <9f23d04b03212987:b0dda39:151a2d3b538:-8000-0000000000004207> <1450355414644> <BEA-000000> <java.lang.NegativeArraySizeException
	at com.octetstring.vde.EntryChanges.readBytes(EntryChanges.java:274)
	at com.octetstring.vde.EntryChanges.<init>(EntryChanges.java:72)
	at com.octetstring.vde.replication.BackendChangeLog.getChange(BackendChangeLog.java:548)
	at com.octetstring.vde.replication.Replicator.run(Replicator.java:180)
	at com.octetstring.vde.replication.Replication.run(Replication.java:339)
> )

chances are that there are corrupted LDAP files in the <domain home>/servers/<server name>/data/ldap/ldapfiles folder. One possible solution is to delete the changelog.data and changelog.index files (take a backup first of these two files) and restart the admin server.

Categories: Java, ldap, Oracle, WebLogic Tags: , , ,

ORA-01003: no statement parsed

16 September 2015 Leave a comment

Not Java-related but since I started doing a bit of PL/SQL lately and I ran into this problem, I will post this. This error, in my case, was caused by having an Oracle keyword defined as a column name. For example the following

OPEN v_customer_recs FOR
         SELECT sc.EVENT_ID,
                sc.OPEN_DATE,
                ND.DESCRIPTION AS COMMENT,  -- This will cause the error
                SC.BC_DATE
           FROM CUSTOMERS sc, NEW_DESCRIPTION ND

will result in a ORA-01003: no statement parsed. The problem is that the COMMENT keyword is used as a column name. If you change this then the error will go away.

Categories: Oracle, PLSQL

How to issue a JSON POST request to Spring Data Rest with a JPA relation

25 November 2014 Leave a comment

Lets say we have a class Company which has a relation to a class User

@Entity
@Table(name = "company")
public class Company implements java.io.Serializable {

	private static final long serialVersionUID = 1L;
	
	private Long id;
	private String name;
	private User user;

	public Company() {
	}

	@Id
	@GeneratedValue(strategy = IDENTITY)
	@Column(name = "id", unique = true, nullable = false)
	public Long getId() {
		return this.id;
	}

	public void setId(Long id) {
		this.id = id;
	}

	@Column(name = "name", nullable = false, length = 200)
	public String getName() {
		return this.name;
	}

	public void setName(String name) {
		this.name = name;
	}

	@ManyToOne(fetch = FetchType.LAZY, optional = false, targetEntity=my.example.User.class)
	@JoinColumn(name = "user_id")
	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

and their corresponding repositories:

@RepositoryRestResource(collectionResourceRel = "company", path = "company")
public interface CompanyRepository extends JpaRepository<Company, Long>  {
}

@RepositoryRestResource(collectionResourceRel = "user", path = "user")
public interface UserRepository extends JpaRepository<User, Long> {

}

In order to add a user to the company (let’s say we want to link this company to the user with id of 2) you will need to issue the following JSON request to the company repository:

{
"name" : "a company name",
"user" : "http://localhost:8086/user/2"
}

The “user” variable should be the URL that is pointing to the user repository.

Categories: Java, Spring, Spring Data Rest Tags: ,

Yet another WTF moment

4 June 2014 5 comments
boolean found = false;
for (int pr=0; pr<promotions.length; pr++) {
    Promotion promotion = promotions[pr];
    if (promotion!=null && promotion.getName().equals(""+availablePromotions[pr][a1].getPackageId())) {
        externalPromotions[pr] = externalPromotions[pr];    // WTF!!! Assigning a value to itself.
        found = true;  // Not sure what this is
        break;
    }
}
found = false;  // As soon as the loop exits this goes back to false again. WTF!!!

The above is an actual snippet of code from a production system (the comments are mine). And yes, I am serious.

Categories: WTF

How to call a web service from Android

24 May 2014 1 comment

By far the easiest way is to use the ksoap2-android API. You need the ksoap2 jar file (with all dependencies) which can be found here and you need to add this to your classpath. In the following sample code we call a free web service, called currency convertor, which has one operation (method) that is is called ConversionRate. If you look at the service dscription (the WSDL file), you will see that this operation takes two parameters, FromCurrency and ToCurrency. Lets say that we want to find out the conversion rate from USD to EUR. We implement the following Activity

package gr.panos.caller;

import java.io.IOException;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.SoapFault;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapPrimitive;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;
import org.xmlpull.v1.XmlPullParserException;

import android.os.AsyncTask;
import android.os.Bundle;
import android.app.Activity;
import android.widget.TextView;

public class ConvertorCaller extends Activity {

	public final static String URL = "http://www.webservicex.net/CurrencyConvertor.asmx";
	public static final String NAMESPACE = "http://www.webserviceX.NET/";
	public static final String SOAP_ACTION = "http://www.webserviceX.NET/ConversionRate";
	private static final String METHOD = "ConversionRate";
	private TextView textView;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_convertor_caller);
		textView = (TextView) findViewById(R.id.textView1);
		AsyncTaskRunner runner = new AsyncTaskRunner();
		runner.execute();
	}

	 private class AsyncTaskRunner extends AsyncTask<String, String, String>{

		 private String resp;

		@Override
		protected String doInBackground(String... params) {
		     try {
		      SoapObject request = new SoapObject(NAMESPACE, METHOD);
		      request.addProperty("FromCurrency", "USD");
		      request.addProperty("ToCurrency", "EUR");

		      SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11);
		      envelope.dotNet = true;
		      envelope.setOutputSoapObject(request);  
		      System.out.println("************ I AM SENDING: " + envelope.bodyOut);
		      
		       HttpTransportSE transport = new HttpTransportSE(URL);
		       try {
		         transport.call(SOAP_ACTION, envelope);
		       } catch (IOException e) {
		         e.printStackTrace();
		       } catch (XmlPullParserException e) {
		         e.printStackTrace();
		     }
		   if (envelope.bodyIn != null) {
			   if (envelope.bodyIn instanceof SoapFault) {
				   String s = ((SoapFault) envelope.bodyIn).faultstring;
				   System.out.println("************ ERROR: " + s);
				   resp = s;
			   } else if (envelope.bodyIn instanceof SoapObject) {
				   SoapObject obj = ((SoapObject) envelope.bodyIn); 
				   System.out.println("**** RESPONSE: " +obj);
				   
				   SoapPrimitive root = (SoapPrimitive) obj.getProperty(0);
				   System.out.println("**** CONVERSION RATE: " +root.toString());
				   
				   resp = root.toString();
			   }
				   
		   }
		 } catch (Exception e) {
		   e.printStackTrace();
		   resp = e.getMessage();
		 }
	     return resp;
	   }

		  /**
		   * 
		   * @see android.os.AsyncTask#onPostExecute(java.lang.Object)
		   */
		  @Override
		  protected void onPostExecute(String result) {
			  textView.setText(resp);
		  }
	
		  /**
		   * 
		   * @see android.os.AsyncTask#onPreExecute()
		   */
		  @Override
		  protected void onPreExecute() {
		  }
		  /**
		   * 
		   * @see android.os.AsyncTask#onProgressUpdate(Progress[])
		   */
		  @Override
		  protected void onProgressUpdate(String... text) {
		  }
	}

}

You also need to define a text view in your layout as well as give the activity INTERNET permission in your manifest file.

And more!

30 January 2014 Leave a comment
if(canBeMultiplied && renewalOfferMultiplier > 0)
    discount = discount * renewalOfferMultiplier;
else
    discount = discount;
Categories: WTF

Even more WTF

29 January 2014 2 comments

And I thought that I had seen everything. But I hadn’t yet seen a wrapper to a String!!

public class OneVariableGenericVO implements java.io.Serializable
{

  private String varName;

  public OneVariableGenericVO()
  {
  }


  public OneVariableGenericVO(String varName)
  {
  	setVarName(varName);
  }

  public String getVarName()
  {
  	return this.varName;
  }

  public void setVarName(String varName)
  {
  	this.varName = varName;
  }

}

SO instead of using a String someone had the brilliant idea to wrap a String into an object and use this instead. What can I say? I am speechless.

Categories: WTF