Scala programming language, Scala tutorials, Scala resources, using Scala with Eclipse IDE / NetBeans / Maven / Java EE / JSF / JPA
Monday, February 27, 2012
Scala Source Code and Density
Wednesday, February 15, 2012
UnproxyableResolutionException Workaround when using Scala Closures and javax.inject CDI Beans Together
@Produces @Named("facebookPhotoImporter") private var fbPhotoImporter: ActorRef = _ @PostConstruct
def init() {
logger.debug("Starting FacebookPhotoImporter actor")
fbPhotoImporter = Actor.actorOf(fbPhotoImporterFactory.get())
fbPhotoImporter.start()
}It will throw:Caused by: org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001437 Normal scoped bean class com.satukancinta.web.Persistence is not proxyable because the type is final or it contains a final method public final javax.enterprise.inject.Instance com.satukancinta.web.Persistence.com$satukancinta$web$Persistence$$fbPhotoImporterFactory() - Managed Bean [class com.satukancinta.web.Persistence] with qualifiers [@Any @Default].
at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:225)
at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:178)
at org.jboss.weld.util.Proxies.getUnproxyableTypesExceptionInt(Proxies.java:193)
at org.jboss.weld.util.Proxies.getUnproxyableTypesException(Proxies.java:167)
at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:110)
at org.jboss.weld.bootstrap.Validator.validateRIBean(Validator.java:126)
at org.jboss.weld.bootstrap.Validator.validateBeans(Validator.java:345)
at org.jboss.weld.bootstrap.Validator.validateDeployment(Validator.java:330)
at org.jboss.weld.bootstrap.WeldBootstrap.validateBeans(WeldBootstrap.java:366)
at org.jboss.as.weld.WeldContainer.start(WeldContainer.java:82)
at org.jboss.as.weld.services.WeldService.start(WeldService.java:89)
... 5 more As you can see, my use code isn't exactly "edge cases".It's actually a pretty common use case: create a Akka actor and pass a factory function to it, as a closure.
The code above doesn't look like it's using a closure, but it actually is when written like this: (same functionality, but still breaks CDI) fbPhotoImporter = Actor.actorOf { fbPhotoImporterFactory.get() }
I can see why CDI has a strict requirement, and I can also understand why Scala implements it the way it is (Scala developers definitely already has a lot of problems working around powerful Scala features into a very restrictive JVM bytecode requirements). This is the price we pay for having a somewhat inferior language (Java, please don't get offended) in the first place. But I as an application developer want to have a quick fix for this issue. Re-coding the class in plain Java is one option, but it turns I don't need to. There is a workaround, by creating a helper method then using it: @Inject private var fbPhotoImporterFactory: Instance[FacebookPhotoImporter] = _
@Produces @Named("facebookPhotoImporter") private var fbPhotoImporter: ActorRef = _
def createFbPhotoImporter() = fbPhotoImporterFactory.get()
@PostConstruct
def init() {
logger.debug("Starting FacebookPhotoImporter actor")
fbPhotoImporter = Actor.actorOf(createFbPhotoImporter)
fbPhotoImporter.start()
} Now Scala is happy and CDI is also happy. Yes it's a bit more verbose but not too bad. And I guess the code is now somewhat more understandable for Java guys. :) Tip: To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Sunday, January 22, 2012
Scala "Bug" with CDI Dependency Injection
public final methods, although the .scala source definesno
public final method at all.There are two things that CDI doesn’t like (which Scala “sometimes” generates):
1.
public final methods2.
public fieldsTo investigate and reproduce these problems I created a scala-cdi project at GitHub.
public final method: The Bug
Referencing a parent field from a closure / inner class triggers this behavior:@RequestScoped @Named class IndexBean { private lazy val log = LoggerFactory.getLogger(classOf[IndexBean]) def testExecutor() = { val executor = Executors.newFixedThreadPool(4); executor.submit(new Runnable() { override def run(): Unit = log.debug("Executor is running") }) } }
$ javap -p IndexBean Compiled from "IndexBean.scala" public class com.soluvas.scalacdi.IndexBean extends java.lang.Object implements scala.ScalaObject{ private org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log; ... public final org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log();
org.jboss.weld.exceptions.UnproxyableResolutionException: WELD-001437 Normal scoped bean class com.soluvas.scalacdi.IndexBean is not proxyable because the type is final or it contains a final method public final org.slf4j.Logger com.soluvas.scalacdi.IndexBean.com$soluvas$scalacdi$IndexBean$$log() - Managed Bean [class com.soluvas.scalacdi.IndexBean] with qualifiers [@Any @Default @Named]. at org.jboss.weld.util.Proxies.getUnproxyableClassException(Proxies.java:225) at org.jboss.weld.util.Proxies.getUnproxyableTypeException(Proxies.java:178) at org.jboss.weld.util.Proxies.getUnproxyableTypesExceptionInt(Proxies.java:193) at org.jboss.weld.util.Proxies.getUnproxyableTypesException(Proxies.java:167) at org.jboss.weld.bootstrap.Validator.validateBean(Validator.java:110)
public final method: Workaround
Create a final local variable to hold the parent instance’s value:def testExecutor() = { val executor = Executors.newFixedThreadPool(4); // this avoids 'log' becoming 'final' like: // private org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log; // public final org.slf4j.Logger com$soluvas$scalacdi$IndexBean$$log(); val log = this.log; executor.submit(new Runnable() { override def run(): Unit = log.debug("Executor is running") }) }
$ javap -p IndexBean Compiled from "IndexBean.scala" public class com.soluvas.scalacdi.IndexBean extends java.lang.Object implements scala.ScalaObject{ private org.slf4j.Logger log; private org.slf4j.Logger log();
public field
I’m not able to reproduce this yet...Tip: To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Sunday, January 1, 2012
Implementing RichFaces ExtendedDataModel for JSF Paging with Spring Data Neo4j and Scala
JSF 2.1 and JBoss RichFaces 4.1.0 make it easy to do server-side paging and sorting, which improves performance of Java EE web applications significantly compared to returning list of all rows from the database and filtering it later in the application.
By implementing ExtendedDataModel, the data model can be used directly by rich:dataTable and rich:dataScroller JSF components.ExtendedDataModel for Spring Data Neo4j Finder/Query Methods To implement this on Neo4j graph database, by using Spring Data Neo4j finder methods we can implement ExtendedDataModel like below: (in Scala programming language) package com.satukancinta.webimport collection.JavaConversions._import org.ajax4jsf.model.ExtendedDataModel
import javax.faces.context.FacesContext
import org.springframework.data.domain.Page
import org.ajax4jsf.model.DataVisitor
import org.springframework.data.neo4j.repository.GraphRepository
import org.springframework.data.domain.PageRequest
import org.springframework.data.neo4j.aspects.core.NodeBacked
import org.ajax4jsf.model.Range
import org.ajax4jsf.model.SequenceRange
import org.slf4j.LoggerFactory
import org.springframework.data.domain.Sort
import org.springframework.data.domain.Sort.Direction
import org.springframework.data.domain.Pageableabstract class FinderModel[E]() extends ExtendedDataModel[E] {
private lazy val log = LoggerFactory.getLogger(classOf[FinderModel[E]])
private lazy val rowCount: Int = {
val result= getRowCountLazy
log.debug("Total rows: {}", result)
result
}
private var rowIndex: Int = _
private var page: Page[E] = _
private var pageData: List[E] = _
private var lastRange: (Int, Int) = _ log.trace("Created {}", this.getClass)
def getRowCountLazy: Int
def find(pageable: Pageable): Page[E] def setRowKey(key: Object): Unit = setRowIndex(key.asInstanceOf[Int])
def getRowKey: Object = getRowIndex: java.lang.Integer
private def loadData(range: Range): Unit = {
val seqRange = range.asInstanceOf[SequenceRange]
val curRange = (seqRange.getFirstRow, seqRange.getRows)
if (lastRange == curRange) {
log.debug("loadData returning cached")
return
}
lastRange = curRange
val pageNum = seqRange.getFirstRow / seqRange.getRows
// ORDER BY name is painfully slow: https://groups.google.com/group/neo4j/t/f2219df41f5500a9
val pageReq = new PageRequest(pageNum, seqRange.getRows/*, Direction.ASC, "y.name"*/)
log.debug("loadData({}, {}) -> PageRequest({}, {})",
Array[Object](seqRange.getFirstRow: java.lang.Long, seqRange.getRows: java.lang.Long,
pageNum: java.lang.Long, seqRange.getRows: java.lang.Long))
val startTime = System.currentTimeMillis
page = find(pageReq)
val findTime = System.currentTimeMillis - startTime
log.debug("Page has {} rows of {} total in {} pages, took {}ms",
Array[Object](page.getSize: java.lang.Long, page.getTotalElements: java.lang.Long,
page.getTotalPages: java.lang.Long, findTime: java.lang.Long))
pageData = page.toList
// val pageIds = pageData.map( _.asInstanceOf[NodeBacked].getNodeId )
// log.debug("Node IDs: {}", pageIds);
} def walk(context: FacesContext, visitor: DataVisitor, range: Range, argument: Object): Unit = {
loadData(range)
for (val index <- 0 to pageData.size - 1) {
visitor.process(context, index, argument)
}
} def isRowAvailable: Boolean = rowIndex < pageData.length def getRowCount: Int = rowCount def getRowData: E = {
val result = pageData(rowIndex) // repository.findOne(rowKey.asInstanceOf[Long])
val node = result.asInstanceOf[NodeBacked]
log.trace("getRowData({}) = #{}: {}",
Array[Object](rowIndex: java.lang.Long, node.getNodeId: java.lang.Long, node))
result
} def getRowIndex: Int = rowIndex
def setRowIndex(index: Int): Unit = rowIndex = index def getWrappedData: Object = { null }
def setWrappedData(wrappedData: Object): Unit = { /* dummy */ }} To use the FinderModel, it's much easier if we create a repository first and add some finder/query methods returning count and Page:public interface InterestRepository extends GraphRepository<Interest> { @Query("START u=node({userId}) MATCH u-[:LIKE]->y RETURN COUNT(y)")
public Long findUserLikeCount(@Param("userId") long userId); // ORDER BY name is still slow: https://groups.google.com/group/neo4j/t/f2219df41f5500a9
// @Query("START u=node({userId}) MATCH u-[:LIKE]->y RETURN y ORDER BY y.name")
@Query("START u=node({userId}) MATCH u-[:LIKE]->y RETURN y")
public Page<Interest> findUserLikes(@Param("userId") long userId, Pageable pageable); }How to create a FinderModel instance from Java : @Inject InterestRepository interestRepo;
private FinderModel<Interest> userLikesModel; @PostConstruct public void init() {
userLikesModel = new FinderModel<Interest>() { @Override
public int getRowCountLazy() {
return interestRepo.findUserLikeCount(user.getNodeId()).intValue();
} @Override
public Page<Interest> find(Pageable pageable) {
return interestRepo.findUserLikes(user.getNodeId(), pageable);
}
};
}And how to use this data model from a JSF Template .xhtml file:<rich:dataTable id="interestTable" var="interest" value="#{userLikes.userLikesModel}" rows="20">
<rich:column>
<f:facet name="header">Name</f:facet>
<h:link outcome="/interests/show?id=#{interest.nodeId}" value="#{interest.name}"/>
</rich:column>
<f:facet name="footer"><rich:dataScroller/></f:facet>
</rich:dataTable>Quite practical, isn't it?
ExtendedDataModel for Spring Data Neo4j RepositoryFinderModel can then be further subclassed to handle any Spring Data Neo4j repository: class GraphRepositoryModel[E]() extends FinderModel[E] {
private var repository: GraphRepository[E] = _
def getRowCountLazy: Int = repository.count.toInt
def find(pageable: Pageable): Page[E] = repository.findAll(pageable) override def getWrappedData: Object = repository
override def setWrappedData(wrappedData: Object): Unit =
repository = wrappedData.asInstanceOf[GraphRepository[E]] }And use it like this:@Inject InterestRepository interestRepo;
private GraphRepositoryModel<Interest> interestModel;
@PostConstruct public void init() {
interestModel = new GraphRepositoryModel<Interest>();
interestModel.setWrappedData(interestRepo);
} Hope this helps.
To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Saturday, December 31, 2011
Scala closures vs Guava collection functions
public Payload<Iterable<Map<String, Object>>> getUserLikes(@PathParam("userId") long userId) {
User user = neo4j.findOne(userId, User.class);
Iterable<Interest> likeInterests = user.getLikeInterests();
Iterable<Map<String, Object>> likes = Iterables.transform(likeInterests, new Function<Interest, Map<String, Object>>() {
@Override
public Map<String, Object> apply(Interest interest) {
HashMap<String, Object> row = new HashMap<String, Object>();
row.put("id", interest.getNodeId());
row.put("name", interest.getName());
return row;
}
});
return new Payload<Iterable<Map<String, Object>>>(likes);
}
And one in Scala programming language : @GET @Path("user/{userId}/likes") @Produces(Array(MediaType.APPLICATION_JSON))
def getUserLikes(@PathParam("userId") userId: Long): Payload[Iterable[Map[String, Object]]] = {
val user = neo4j.findOne(userId, classOf[User])
val likeInterests = user.getLikeInterests
val likes = likeInterests.map(interest =>
Map("id"->interest.getNodeId, "name"->interest.getName) )
new Payload(likes)
}Is Scala hard to read? I'll leave it to you to decide. :-) To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Coding JSON REST JAX-RS Service Application to Access Neo4j Database in Scala
public class NodeResource { private transient Logger logger = LoggerFactory.getLogger(NodeResource.class);
@Inject Neo4jTemplate neo4j;
@Inject InterestRepository interestRepo;
@GET @Path("interest") @Produces(MediaType.APPLICATION_JSON)
public Iterable<Interest> interest() {
ClosableIterable<Interest> records = neo4j.findAll(Interest.class);
return records;
} @GET @Path("user") @Produces(MediaType.APPLICATION_JSON)
public Payload<User> getUser() {
return new Payload<User>(neo4j.findOne(5L, User.class));
} @POST @Path("interest")
@Consumes(MediaType.APPLICATION_JSON)
@Produces(MediaType.APPLICATION_JSON)
public Response createInterest(Payload<Interest> payload) {
logger.debug("createInterest {}", payload.data);
Interest interest = payload.data;
interest.persist();
return Response.created(URI.create(String.format("interest/%d", interest.getNodeId())))
.entity(new Payload<Interest>(interest)).build();
} @DELETE @Path("interest/{id}")
public Response deleteInterest(@PathParam("id") long id) {
try {
Interest node = neo4j.findOne(id, Interest.class);
node.remove();
return Response.ok("deleted").build();
} catch (DataRetrievalFailureException e) {
return Response.status(Status.NOT_FOUND).entity(e.getMessage()).build();
}
} @GET @Path("interest/by/facebookId/{facebookId}")
@Produces(MediaType.APPLICATION_JSON)
public Payload<Interest> findInterestByFacebookId(@PathParam("facebookId") long facebookId) {
logger.debug("findInterestByFacebookId {}", facebookId);
Interest interest = interestRepo.findByFacebookId(facebookId);
if (interest == null)
throw new WebApplicationException(Response.status(Status.NOT_FOUND).entity("Interest with facebookId="+ facebookId +" not found").build());
return new Payload<Interest>(interest);
} }
Scala programming language version:@Path("node") @Stateless
class NodeResource { private lazy val logger = LoggerFactory.getLogger(classOf[NodeResource])
@Inject var neo4j: Neo4jTemplate = _
@Inject var interestRepo: InterestRepository = _
@GET @Path("interest") @Produces(Array(MediaType.APPLICATION_JSON))
def interest: Iterable[Interest] = neo4j.findAll(classOf[Interest]) @GET @Path("user") @Produces(Array(MediaType.APPLICATION_JSON))
def getUser: Payload[User] = new Payload[User](neo4j.findOne(5L, classOf[User])) @POST @Path("interest")
@Consumes(Array(MediaType.APPLICATION_JSON))
@Produces(Array(MediaType.APPLICATION_JSON))
def createInterest(payload: Payload[Interest]): Response = {
logger.debug("createInterest {}", payload.data)
val interest = payload.data
interest.persist
Response.created(URI.create(String.format("interest/%d", interest.getNodeId)))
.entity(new Payload[Interest](interest)).build
} @DELETE @Path("interest/{id}")
def deleteInterest(@PathParam("id") id: Long): Response = {
try {
val node = neo4j.findOne(id, classOf[Interest])
node.remove
Response.ok("deleted").build
} catch {
case e: DataRetrievalFailureException =>
Response.status(Status.NOT_FOUND).entity(e.getMessage).build
}
} @GET @Path("interest/by/facebookId/{facebookId}")
@Produces(Array(MediaType.APPLICATION_JSON))
def findInterestByFacebookId(@PathParam("facebookId") facebookId: Long): Payload[Interest] = {
logger.debug("findInterestByFacebookId {}", facebookId)
val interest = interestRepo.findByFacebookId(facebookId)
if (interest == null)
throw new WebApplicationException(Response.status(Status.NOT_FOUND).entity("Interest with facebookId="+ facebookId +" not found").build
new Payload[Interest](interest)
} }
Apart from less code and cruft, Scala code is not much different in structure. If there are list processing functions or closures, then Scala code will read much easier, while the Java code will use Guava library and clunky syntax (at least until Java 8 arrives).
To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Graph Analysis with Scala and Spring Data Neo4j
import java.util.Map;import javax.enterprise.context.ApplicationScoped;
import javax.inject.Inject;
import javax.inject.Named; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.neo4j.conversion.Result;
import org.springframework.data.neo4j.support.Neo4jTemplate; import com.google.common.base.Function;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.satukancinta.domain.User; /**
* @author ceefour
* Various analysis of the social graph.
*/
@Named @ApplicationScoped
public class GraphAnalysis {
private transient Logger logger = LoggerFactory.getLogger(GraphAnalysis.class);
@Inject Neo4jTemplate neo4j;
public List<MutualLikeRow> getMutualLikesLookup(User user) {
logger.debug("getMutualLikesLookup {}/{}", user.getNodeId(), user);
Result<Map<String, Object>> rows = neo4j.query("START x=node("+ user.getNodeId() +") MATCH x-[:LIKE]->i<-[:LIKE]-y RETURN id(y) AS id, y.name AS name, COUNT(*) AS mutualLikeCount", null);
Iterable<MutualLikeRow> result = Iterables.transform(rows, new Function<Map<String, Object>, MutualLikeRow>() {
@Override
public MutualLikeRow apply(Map<String, Object> arg) {
return new MutualLikeRow((Long)arg.get("id"), (Integer)arg.get("mutualLikeCount"),
(String)arg.get("name"));
}
});
return Lists.newArrayList(result);
} }
Scala programming language version:package com.satukancinta.web
import collection.JavaConversions._
import org.slf4j._
import javax.inject.Inject
import org.springframework.data.neo4j.support.Neo4jTemplate
import com.satukancinta.domain.User
import javax.enterprise.context.ApplicationScoped
import javax.inject.Named/**
* @author ceefour
* Analysis functions of friend network graph.
*/
@Named @ApplicationScoped
class GraphAnalysis { private lazy val logger = LoggerFactory.getLogger(classOf[GraphAnalysis])
@Inject private var neo4j: Neo4jTemplate = _
def getMutualLikesLookup(user: User): java.util.List[MutualLikeRow] = {
logger.debug("getMutualLikesLookup {}/{}", user.getNodeId, user)
val rows = neo4j.query(
"START x=node("+ user.getNodeId() +") MATCH x-[:LIKE]->i<-[:LIKE]-y RETURN id(y) AS id, y.name AS name, COUNT(*) AS mutualLikeCount", null)
val result = rows.map( r =>
new MutualLikeRow(r("id").asInstanceOf[Long],
r("mutualLikeCount").asInstanceOf[Integer].longValue,
r("name").asInstanceOf[String]) )
.toList
result.sortBy(-_.mutualLikeCount)
}
}
As you can see, the Scala version is not only much more concise, easier to understand, but actually has added functionality (sorted using .sortBy) with less code. Thanks to collection functions and closure support. To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Wednesday, October 12, 2011
How to Exclude Scala/Java Source Files by Name in sbt
src/main/scala. You can exclude source files by name (butler.scala in the example below) like: excludeFilter in unmanagedSources := "butler.scala"
Read more on How to exclude .scala source file in project folder - sbt Google Groups, also checkout Classpaths - sbt Wiki.
To learn more about Scala programming, I recommend Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Tuesday, June 21, 2011
Using UnboundID LDAP SDK Directory API from Scala
Indeed the UnboundID LDAP SDK is really easy to use, and it's better with powerful Scala & its versatile interpreter for a quick ride. :-)Learn Scala programming language quicker! Get Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition.
Connect & Bind using UnboundID LDAP SDK and Scala
ceefour@annafi:~/vendor/unboundid-ldapsdk-2.2.0-se$ scala -cp unboundid-ldapsdk-se.jar Welcome to Scala version 2.9.0.1 (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_25). Type in expressions to have them evaluated. Type :help for more information. scala> import com.unboundid.ldap.sdk._ import com.unboundid.ldap.sdk._ scala> val con = new LDAPConnection con: com.unboundid.ldap.sdk.LDAPConnection = LDAPConnection(not connected) scala> con.connect("localhost", 10389) scala> con.bind("uid=admin,ou=system","password") res5: com.unboundid.ldap.sdk.BindResult = LDAPResult(resultCode=0 (success), messageID=1)Connect & Bind via SSL
scala> import com.unboundid.util.ssl._ import com.unboundid.util.ssl._ scala> var sslUtil = new SSLUtil( new TrustAllTrustManager() ) sslUtil: com.unboundid.util.ssl.SSLUtil = com.unboundid.util.ssl.SSLUtil@43763e0b scala> var socketFactory = sslUtil.createSSL createSSLContext createSSLServerSocketFactory createSSLSocketFactory scala> var socketFactory = sslUtil.createSSLSocketFactory socketFactory: javax.net.ssl.SSLSocketFactory = com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl@43d7a5a scala> val con = new LDAPConnection LDAPConnection LDAPConnectionInternals LDAPConnectionOptions LDAPConnectionPool LDAPConnectionPoolHealthCheck LDAPConnectionPoolHealthCheckThread LDAPConnectionPoolStatistics LDAPConnectionReader LDAPConnectionStatistics scala> val con = new LDAPConnection(socketFactory, "localhost", 10636) con: com.unboundid.ldap.sdk.LDAPConnection = LDAPConnection(connected to localhost:10636) scala> con.bind("uid=admin,ou=system","password") res18: com.unboundid.ldap.sdk.BindResult = LDAPResult(resultCode=0 (success), messageID=1)Search
scala> val results=con.search("ou=system",SearchScope.SUB,"(uid=admin)") results: com.unboundid.ldap.sdk.SearchResult = SearchResult(resultCode=0 (success), messageID=3, entriesReturned=1, referencesReturned=0) scala> results.getSearchEntries res8: java.util.List[com.unboundid.ldap.sdk.SearchResultEntry] = [SearchResultEntry(dn='uid=admin,ou=system', messageID=3, attributes={Attribute(name=uid, values={'admin'}), Attribute(name=keyAlgorithm, values={'RSA'}), Attribute(name=sn, values={'administrator'}), Attribute(name=objectClass, values={'person', 'organizationalPerson', 'inetOrgPerson', 'tlsKeyInfo', 'top'}), Attribute(name=displayName, values={'Directory Superuser'}), Attribute(name=cn, values={'system administrator'}), Attribute(name=publicKey, base64Values={'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJjX2EbUDyBZYFPfsSNMZRsW3mLc/KiKRO6pck3J3eFMKErXA7jxpiho/Eoc6RWgxut2K3aITnQZIl1hHF6Hv30CAwEAAQ=='}), Attribute(name=privateKeyFormat, values={'PKCS#8'}), Attribute(name=publicKeyFormat, values={'X.509'}), Attribute(name=privateKey, ba... scala> results.getSearchEntries.get(0) res11: com.unboundid.ldap.sdk.SearchResultEntry = SearchResultEntry(dn='uid=admin,ou=system', messageID=3, attributes={Attribute(name=uid, values={'admin'}), Attribute(name=keyAlgorithm, values={'RSA'}), Attribute(name=sn, values={'administrator'}), Attribute(name=objectClass, values={'person', 'organizationalPerson', 'inetOrgPerson', 'tlsKeyInfo', 'top'}), Attribute(name=displayName, values={'Directory Superuser'}), Attribute(name=cn, values={'system administrator'}), Attribute(name=publicKey, base64Values={'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJjX2EbUDyBZYFPfsSNMZRsW3mLc/KiKRO6pck3J3eFMKErXA7jxpiho/Eoc6RWgxut2K3aITnQZIl1hHF6Hv30CAwEAAQ=='}), Attribute(name=privateKeyFormat, values={'PKCS#8'}), Attribute(name=publicKeyFormat, values={'X.509'}), Attribute(name=privateKey, base64Values={'MII...Compare
scala> con.compare("uid=admin,ou=system", "userPassword", "password") res12: com.unboundid.ldap.sdk.CompareResult = LDAPResult(resultCode=5 (compare false), messageID=4, opType='compare', matchedDN='uid=admin,ou=system') scala> con.compare("uid=admin,ou=system", "uid", "admin") res13: com.unboundid.ldap.sdk.CompareResult = LDAPResult(resultCode=6 (compare true), messageID=5, opType='compare', matchedDN='uid=admin,ou=system')Get Entry & Attribute Value
scala> val entry = con.getEntry("uid=admin,ou=system") entry: com.unboundid.ldap.sdk.SearchResultEntry = SearchResultEntry(dn='uid=admin,ou=system', messageID=7, attributes={Attribute(name=uid, values={'admin'}), Attribute(name=keyAlgorithm, values={'RSA'}), Attribute(name=sn, values={'administrator'}), Attribute(name=objectClass, values={'person', 'organizationalPerson', 'inetOrgPerson', 'tlsKeyInfo', 'top'}), Attribute(name=displayName, values={'Directory Superuser'}), Attribute(name=cn, values={'system administrator'}), Attribute(name=publicKey, base64Values={'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJjX2EbUDyBZYFPfsSNMZRsW3mLc/KiKRO6pck3J3eFMKErXA7jxpiho/Eoc6RWgxut2K3aITnQZIl1hHF6Hv30CAwEAAQ=='}), Attribute(name=privateKeyFormat, values={'PKCS#8'}), Attribute(name=publicKeyFormat, values={'X.509'}), Attribute(name=privateKey, base64Values={'MII... scala> entry.getAttribute getAttribute getAttributeValue getAttributeValueAsBoolean getAttributeValueAsDN getAttributeValueAsDate getAttributeValueAsInteger getAttributeValueAsLong getAttributeValueByteArrays getAttributeValueBytes getAttributeValues getAttributes getAttributesWithOptions scala> entry.getAttribute def getAttribute(String): Attribute def getAttribute(String, schema.Schema): Attribute scala> entry.getAttribute("userPassword") res16: com.unboundid.ldap.sdk.Attribute = Attribute(name=userPassword, values={'{SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g='}) scala> entry.getAttributeValue("userPassword") res17: java.lang.String = {SHA}W6ph5Mm5Pz8GgiULbPgzG37mj9g=Scala 2.9.0.1 final version released: programming language with parallel features for Java VM
UPDATE: Scala 2.9.0.1 has replaced 2.9.0 as it hot-fixed several important bugs.
We are happy to announce the release of the new stable release of the Scala distribution. The new Scala 2.9.0 final is available from our Download Page. The Scala 2.9.0 codebase includes several additions, notably the new Parallel Collections, but it also introduces improvements on many existing features, and contains many bug fixes.
Scala 2.9.0 binaries are available for the following libraries:
- Dispatch 0.7.8 and 0.8.1
- Unfiltered 0.3.2
- Spde 0.3.1
Of course.
Here are some recommended learning resources on Scala programming language:
- Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition
- Programming Scala: Scalability = Functional Programming + Objects (Animal Guide)
- Programming Scala: Tackle Multi-Core Complexity on the Java Virtual Machine (Pragmatic Programmers)
- Beginning Scala (Expert's Voice in Open Source)
Also, the Typesafe Stack is also out, which brings together Scala, Akka, and a few other things to get one up-and-running quickly. Much fun.
On the collection side of things, one of the first questions I saw was: do parallel collections share a common interface with standard collections. The answer is yes, they do, but not one that existed in 2.8.1. You see, a trouble with parallel collections is that, now that they are available, people will probably be passing them around. If they could be passed to old code -- as it was briefly contemplated -- that old code could crash in mysterious ways. In fact, it happens with REPL itself. For that reason, ALL of your code comes with a guarantee that it will only accept sequential collections. In other words, Iterable, Seq, Set, etc, they all now share a guarantee to be sequential, which means you cannot pass a parallel sequence to a method expecting Seq. The parallel collections start with Par: ParIterable, ParSeq, ParSet and ParMap. No ParTraversable for now. These are guaranteed to be parallel. They can be found inside scala.collection.parallel, scala.collection.parallel.immutable, etc. You can also get a parallel collection just by calling the ".par" method on it, and, similarly, the ".seq" method will return a sequential collection.Now, if you want your code to not care whether it receives a parallel or sequential collection, you should prefix it with Gen: GenTraversable, GenIterable, GenSeq, etc. These can be either parallel or sequential. And, now, something fun to try out:def p[T](coll: collection.GenIterable[T]) = coll foreach println; p(1 to 20); p((1 to 20).par)
I highly recommend the following books for more information about Scala programming language:
- Programming in Scala: A Comprehensive Step-by-Step Guide, 2nd Edition
- Programming Scala: Scalability = Functional Programming + Objects (Animal Guide)
- Programming Scala: Tackle Multi-Core Complexity on the Java Virtual Machine (Pragmatic Programmers)
- Beginning Scala (Expert's Voice in Open Source)
Copied mostly verbatim from this announcement and that announcement.
Sunday, December 26, 2010
How to Dump/Inspect Object or Variable in Java
b: scala.collection.immutable.Map[java.lang.String,Any] scala> b
res1: scala.collection.immutable.Map[java.lang.String,Any] = Map((name,Yudha), (age,27)) Inside our application, especially in Java programming language (although the techniques below obviously works with any JVM language like Scala and Groovy) sometimes we want to inspect/dump the content of an object/value. Probably for debugging or logging purposes. My two favorite techniques is just to serialize the Java object to JSON and/or XML. An added benefit is that it's possible to deserialize the dumped object representation back to an actual object if you want.
JSON Serialization with Jackson
Depend on Jackson (using Maven):<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.6.3</version>
</dependency>
Then use it:
import org.codehaus.jackson.JsonGenerationException;
import org.codehaus.jackson.map.JsonMappingException;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.map.SerializationConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; ..
Logger logger = LoggerFactory.getLogger(getClass());
@Test
public void level() throws ServiceException, JsonGenerationException, JsonMappingException, IOException {
MagentoServiceLocator locator = new MagentoServiceLocator();
Mage_Api_Model_Server_HandlerPortType port = locator.getMage_Api_Model_Server_HandlerPort();
String sessionId = port.login("...", "...");
logger.info(String.format("Session ID = %s", sessionId));
Map[] categories = (Map[]) port.call(sessionId, "catalog_category.level", new Object[] { null, null, 2 } );
ObjectMapper mapper = new ObjectMapper();
mapper.configure(SerializationConfig.Feature.INDENT_OUTPUT, true);
logger.info( mapper.writeValueAsString(categories) );
} Example output : 6883 [main] INFO id.co.bippo.shop.magentoclient.AppTest - [ {
"position" : "1",
"level" : "2",
"is_active" : "1",
"name" : "Gamis",
"category_id" : "3",
"parent_id" : 2
}, {
"position" : "2",
"level" : "2",
"is_active" : "1",
"name" : "Celana",
"category_id" : "5",
"parent_id" : 2
} ]
XML Serialization with XStream
As a pre-note, XStream can also handle JSON with either Jettison or its own JSON driver, however people usually prefer Jackson than XStream for JSON serialization. Maven dependency for XStream:<dependency>
<groupId>xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.2.2</version>
</dependency>
Use it:
import java.io.IOException;
import java.rmi.RemoteException;
import java.util.Map; import javax.xml.rpc.ServiceException; import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import com.thoughtworks.xstream.XStream;
...
@Test
public void infoXml() throws ServiceException, RemoteException {
MagentoServiceLocator locator = new MagentoServiceLocator();
Mage_Api_Model_Server_HandlerPortType port = locator.getMage_Api_Model_Server_HandlerPort();
String sessionId = port.login("...", "...");
logger.info(String.format("Session ID = %s", sessionId));
Map category = (Map) port.call(sessionId, "catalog_category.info",
new Object[] { 3 } );
XStream xstream = new XStream();
logger.info( xstream.toXML(category) );
} Sample output: 5949 [main] INFO id.co.bippo.shop.magentoclient.AppTest - <map>
<entry>
<string>position</string>
<string>1</string>
</entry>
<entry>
<string>custom_design</string>
<string></string>
</entry>
<entry>
<string>custom_use_parent_settings</string>
<string>0</string>
</entry>
<entry>
<string>custom_layout_update</string>
<string></string>
</entry>
<entry>
<string>include_in_menu</string>
<string>1</string>
</entry>
<entry>
<string>custom_apply_to_products</string>
<string>0</string>
</entry>
<entry>
<string>meta_keywords</string>
<string>gamis, busana muslim</string>
</entry>
<entry>
<string>available_sort_by</string>
<string></string>
</entry>
<entry>
<string>url_path</string>
<string>gamis.html</string>
</entry>
<entry>
<string>children</string>
<string></string>
</entry>
<entry>
<string>landing_page</string>
<null/>
</entry>
<entry>
<string>display_mode</string>
<string>PRODUCTS</string>
</entry>
<entry>
<string>level</string>
<string>2</string>
</entry>
<entry>
<string>description</string>
<string>Gamis untuk muslimah</string>
</entry>
<entry>
<string>name</string>
<string>Gamis</string>
</entry>
<entry>
<string>path</string>
<string>1/2/3</string>
</entry>
<entry>
<string>created_at</string>
<string>2010-12-24 11:37:41</string>
</entry>
<entry>
<string>children_count</string>
<string>0</string>
</entry>
<entry>
<string>is_anchor</string>
<string>1</string>
</entry>
<entry>
<string>url_key</string>
<string>gamis</string>
</entry>
<entry>
<string>parent_id</string>
<int>2</int>
</entry>
<entry>
<string>filter_price_range</string>
<null/>
</entry>
<entry>
<string>all_children</string>
<string>3</string>
</entry>
<entry>
<string>is_active</string>
<string>1</string>
</entry>
<entry>
<string>page_layout</string>
<string></string>
</entry>
<entry>
<string>image</string>
<null/>
</entry>
<entry>
<string>category_id</string>
<string>3</string>
</entry>
<entry>
<string>default_sort_by</string>
<null/>
</entry>
<entry>
<string>custom_design_from</string>
<null/>
</entry>
<entry>
<string>updated_at</string>
<string>2010-12-24 11:37:41</string>
</entry>
<entry>
<string>meta_description</string>
<string>Jual baju gamis untuk muslim</string>
</entry>
<entry>
<string>custom_design_to</string>
<null/>
</entry>
<entry>
<string>path_in_store</string>
<null/>
</entry>
<entry>
<string>meta_title</string>
<string>Gamis</string>
</entry>
<entry>
<string>increment_id</string>
<null/>
</entry>
</map> Which one is better? I personally prefer JSON, but fortunately, you always have a choice. :-)
Monday, December 20, 2010
Eclipse RAP Single Sourcing Awesomeness (with EMF Editor and Teneo+Hibernate as bonus!)
- Do not hard-depend on org.eclipse.ui plugin. Either depend on both org.eclipse.ui and org.eclipse.rap.ui plugins as optional dependencies, or import the specific packages. I prefer optional dependency on both plugins because it's much faster and easier.
- Be aware that there will be multiple sessions at once.
- 2D Drawing functions are not yet fully available. (and I guess will never be available)
See the Eclipse RAP FAQ on Single Sourcing for more information.