Friday, June 29, 2018

Some flaw happened in clearing the memory

There is some amendment being done in clearMemory() for a very long time ago. I can't recall what I did last time, the code seemed likely been done in a rush and there are not test well. This is the piece I mention in this post:
void FileBot::clearMemory(FileNode *fileNode)
{
    bool lastNode = false;

    // this case will happened only when the root is supply
    if( fileList.size() == 0 || (fileList.begin())->sibling.empty() ) {
        BOOST_LOG_TRIVIAL(info) << "current node has no sibling: " << endl;
        return;
    }

    // if this is the only node in the container
    // clean up the container and then bail
    FileNode *firstNode = &*(fileList.begin());

    // test on first node is empty
    if( !firstNode->sibling.empty() && firstNode->sibling.size() == 0 ) {
        BOOST_LOG_TRIVIAL(info) << "This is the only node. Root size [" << fileList.size() << "]";
        fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode());
        return;
    }

    // if this is not the only node in the container
    // clean up the container recursively
    if( fileNode == NULL ) {
       BOOST_LOG_TRIVIAL(info) << "current node has no sibling: " << fileNode;

       fileNode = &*(fileList.begin());
       fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode());
       lastNode = true;
    }
    else {
        BOOST_LOG_TRIVIAL(info) << "current node has sibling: " << fileNode << " : " << fileNode->getName() << " sibling : " << fileNode->sibling.size();

        if( fileNode->sibling.size() > 0 ) {
            for( FileNodeListType::iterator it = fileNode->sibling.begin(); it != fileNode->sibling.end(); it++ ) {
                clearMemory(&*(it));
            }
        }
        else {
            cout << fileNode << " has no more sibling." << endl;
            return;
        }

        BOOST_LOG_TRIVIAL(info) << "cleaning sibling memory for this node: " << fileNode << " node name: " << fileNode->getName();
        fileNode->sibling.erase_and_dispose(fileNode->sibling.begin(), fileNode->sibling.end(), DisposeFileNode());
    }

    if( lastNode ) {
        BOOST_LOG_TRIVIAL(info) << "Reacing the root. Root size [" << fileList.size() << "]";
        fileList.erase_and_dispose(fileList.begin(), fileList.end(), DisposeFileNode());
    }
}
In the past few days I sat down just to review my test case, I found out some of the code was not covered by the test cases. Those uncover pieces are 16-20, 24-30, and 49-52. I was shocked when I see those uncovered pieces. I wonder whether those pieces are unused code since none of the test cases cover them up.

I study the code carefully, test run for few times and finally I got a fantastic conclusion. There are 2 sections are required for this function to carry on its job; first section would be the validation, this will validate whether the container, as well as, the FileNode's sibling contain any elements in it? This is the one:
    // this case will happened only when the root is supply
    if( fileList.size() == 0 || (fileList.begin())->sibling.empty() ) {
        BOOST_LOG_TRIVIAL(info) << "current node has no sibling: " << endl;
        return;
    }
Whereas the second section would be the core logic focus on cleaning the container, as well as, the sibling of each FileNode. Here is the one:
    BOOST_LOG_TRIVIAL(info) << "current node has sibling: " << fileNode << " : " << fileNode->getName() << " sibling : " << fileNode->sibling.size();

    if( fileNode->sibling.size() > 0 ) {
        for( FileNodeListType::iterator it = fileNode->sibling.begin(); it != fileNode->sibling.end(); it++ ) {
            clearMemory(&*(it));
        }
    }
    else {
         cout << fileNode << " has no more sibling." << endl;
         return;
    }

    BOOST_LOG_TRIVIAL(info) << "cleaning sibling memory for this node: " << fileNode << " node name: " << fileNode->getName();
    fileNode->sibling.erase_and_dispose(fileNode->sibling.begin(), fileNode->sibling.end(), DisposeFileNode());
Now the code is much more readable. Don't you agree? Oh! by the way, I already moved this function into the destructor since I'll invoke this function at the end of each unit test. Don't you feel much better?
FileBot::~FileBot()
{
    clearMemory(&*(fileList.begin()));
}

Invocation WsimportTool failed?!!

Hey there, I am making a new friend today. The meet this new friend in Eclipse Photon when I was creating a brand new web service project. Here is the story, when I first started the project, I only have the WSDL file ready in the source folder, and then I have the jaxws-maven-plugin in my pom file, like this:
  <plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>jaxws-maven-plugin</artifactId>
    <version>2.5</version>
    <executions>
      <execution>
        <goals>
          <goal>wsimport</goal>
        </goals>
        <configuration>
          <keep>true</keep>
          <extension>true</extension>
          <sourceDestDir>${basedir}/src/main/java</sourceDestDir>
          <packageName>org.huahsin68.ws</packageName>
          <wsdlDirectory>${basedir}/src/main/resources</wsdlDirectory>
          <wsdlFiles>
            <wsdlFile>hello.wsdl</wsdlFile>
          </wsdlFiles>
        </configuration>
      </execution>
    </executions>
  </plugin>
Then this error immediately shown up right after the execution tag as shown below. What was that mean? I don’t even understand why the WsimportTool could fail?
Invocation of com.sun.tools.ws.wscompile.WsimportTool failed - check output (org.codehaus.mojo:jaxws-maven-plugin:2.5:wsimport:default:generate-sources)

org.apache.maven.plugin.MojoExecutionException: Invocation of com.sun.tools.ws.wscompile.WsimportTool failed - check output
 at org.codehaus.mojo.jaxws.AbstractJaxwsMojo.exec(AbstractJaxwsMojo.java:485)
 at org.codehaus.mojo.jaxws.WsImportMojo.processLocalWsdlFiles(WsImportMojo.java:339)
 at org.codehaus.mojo.jaxws.WsImportMojo.executeJaxws(WsImportMojo.java:292)
 at org.codehaus.mojo.jaxws.MainWsImportMojo.executeJaxws(MainWsImportMojo.java:54)
 at org.codehaus.mojo.jaxws.AbstractJaxwsMojo.execute(AbstractJaxwsMojo.java:386)
 at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:137)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:331)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1362)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl$11.call(MavenImpl.java:1)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:177)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:112)
 at org.eclipse.m2e.core.internal.embedder.MavenImpl.execute(MavenImpl.java:1360)
 at org.eclipse.m2e.core.project.configurator.MojoExecutionBuildParticipant.build(MojoExecutionBuildParticipant.java:52)
 at org.eclipse.m2e.core.internal.builder.MavenBuilderImpl.build(MavenBuilderImpl.java:137)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$1.method(MavenBuilder.java:172)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$1.method(MavenBuilder.java:1)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod$1$1.call(MavenBuilder.java:115)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:177)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:112)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod$1.call(MavenBuilder.java:105)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.executeBare(MavenExecutionContext.java:177)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:151)
 at org.eclipse.m2e.core.internal.embedder.MavenExecutionContext.execute(MavenExecutionContext.java:99)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder$BuildMethod.execute(MavenBuilder.java:86)
 at org.eclipse.m2e.core.internal.builder.MavenBuilder.build(MavenBuilder.java:200)
 at org.eclipse.core.internal.events.BuildManager$2.run(BuildManager.java:795)
 at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
 at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:216)
 at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:259)
 at org.eclipse.core.internal.events.BuildManager$1.run(BuildManager.java:312)
 at org.eclipse.core.runtime.SafeRunner.run(SafeRunner.java:42)
 at org.eclipse.core.internal.events.BuildManager.basicBuild(BuildManager.java:315)
 at org.eclipse.core.internal.events.BuildManager.basicBuildLoop(BuildManager.java:367)
 at org.eclipse.core.internal.events.BuildManager.build(BuildManager.java:388)
 at org.eclipse.core.internal.events.AutoBuildJob.doBuild(AutoBuildJob.java:142)
 at org.eclipse.core.internal.events.AutoBuildJob.run(AutoBuildJob.java:232)
 at org.eclipse.core.internal.jobs.Worker.run(Worker.java:60)
Googling the around some said that this is a defect from the IDE; some even said that this could be caused by the JAVA version issue; some even said JDK 8 is not supported in Eclipse Mars version. Does it true? Not really. Firstly, I issued a command mvn clean and then follow by mvn generate-sources. The error is gone! What a weird day?!!

Sunday, June 24, 2018

Verifying the "files" are being loaded correctly

I'd made a function that its sole responsibility is to verify the files have successfully loaded into memory. Following code snippet shows my hard work:
std::list<string> FileBot::getLoadedFiles(FileNode *fileNode)
{
    std::list<string> mlist;

    BOOST_LOG_TRIVIAL(info) << "current root address : " << fileNode;

    if( fileNode == nullptr || fileNode->sibling.size() == 0 )
        return mlist;

    for( FileNodeListType::iterator it = fileNode->sibling.begin(); it != fileNode->sibling.end(); ++it )
    {
        FileNode *n = (&*it);

        if( n->getType() == 'd' ) {
            std::list<string> subList;
            subList = getLoadedFiles(n);

            mlist.insert(mlist.begin(), subList.begin(), subList.end());
        }
        else {
            string filePath = constructPathAddress(n);
            mlist.push_back(filePath);

            BOOST_LOG_TRIVIAL(info) << "filePath : " << filePath;
        }
    }

    return mlist;
}
I need this function in my unit test code to ensure constructParentPath() and constructChildPath() are doing their job correctly. Take the following test case for example:
BOOST_AUTO_TEST_CASE(TL_5, *boost::unit_test::precondition(skipTest(true)))
{
    BOOST_TEST_MESSAGE("TC8 : one file is captured without sub folder");

    string testPathA = current_path().string() + string(1, path::preferred_separator) + "FolderA";
    createTestFile(testPathA, 1);

#if defined(WIN32)
    BOOST_TEST(testPathA == "D:\\workspaceqt\\backupUtil\\backupUtilUnitTest\\FolderA");
#else
    BOOST_TEST(testPathA == "/home/kokhoe/workspaceqt/debug/FolderA");
#endif

    FileBotUnderTest fb;
    FileNode *root = nullptr;
    if( (root = fb.constructParentPath(testPathA)) == nullptr ) {
        BOOST_TEST_MESSAGE("Initialization failed.");
        return;
    }

    string path = fb.getParentPathAddress();

#if defined(WIN32)
    BOOST_TEST(path == "D:\\workspaceqt\\backupUtil\\backupUtilUnitTest\\FolderA\\");
#else
    BOOST_TEST(path == "/home/kokhoe/workspaceqt/debug/FolderA/");
#endif

    fb.constructChildPath(root);

    // verify the file name was captured
    std::list<string> files = fb.getLoadedFiles(root);

    BOOST_TEST(files.size() == 1);

#if defined(WIN32)
    if( std::find(files.begin(), files.end(), "D:/workspaceqt/backupUtil/backupUtilUnitTest/FolderA/file_1.txt") == files.end() )
        BOOST_TEST(false);
#else
    if( std::find(files.begin(), files.end(), "/home/kokhoe/workspaceqt/debug/FolderA/file_1.txt") == files.end() )
        BOOST_TEST(false);
#endif

    destroyTestFile(testPathA);
}
This function is gets invoked right after the "files" are loaded into memory. There are not the physical file, it's just a shadow. To effectively process the files stored in the sub folder, it will invoke itself to dive into the sub folder bringing together a reference of the current path, until it has iterated through the end of the path. That is the reason why this function has a parameter of FileNode type. But there was a question come into my mind, why do I still need to pass the root (a reference value came from constructParentPath() in the unit test mention above) into this function since the FileBot class already got a reference to this value?
class FileBot
{
   ...
   ...

private:
    // *root should never be NULL
    FileNode *root = nullptr;       // store the a reference to root path

}
I know this was stupid. The initial objective is to create a function that could verify the "files" that has been loaded into memory are done correctly. I think this function is only used for the unit test purpose. I'll just leave it as it is.

Tuesday, June 19, 2018

Making a contract first web service with Spring Boot

I have been told that Spring Boot is a great tool to learn. What do I think? In order to get my hand dirty on that, I've chosen to use it to develop a web service project. Well, I'd spend almost an hour plus to launch a web service, able to accept a request and provide a response. It was really damn amazing.

Unlike the tutorial I found on the Internet, my job scope doesn't work in that way. It is the WSDL file was created first, a.k.a. contract-first, but the tutorial I found on the Internet are contract-last. Wait, there are still hope, I found following sample that could help out.

Sample 1
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter
{
   @Bean(name = "services")
   public Wsdl11Definition defaultWsdl11Definition() {
      SimpleWsdl11Definition wsdl11Definition = new SimpleWsdl11Definition();
      wsdl11Definition.setWsdl(new ClassPathResource("/schema/MyWsdl.wsdl")); //your wsdl location
      return wsdl11Definition;
   }
}
Sample 2
@EnableWs
@Configuration
public class WebServiceConfig extends WsConfigurerAdapter
{
   @Bean(name = "wsdlname")
   public DefaultWsdl11Definition defaultWsdl11Definition (XsdSchema cityRequestSchema) {
      DefaultWsdl11Definition wsdl11Definition = new DefaultWsdl11Definition();
      wsdl11Definition.setRequestSuffix("ByCountry");
      wsdl11Definition.setResponseSuffix("City");
      wsdl11Definition.setPortTypeName("Hotelport");
      wsdl11Definition.setLocationUri("/ProjectName");
      wsdl11Definition.setTargetNamespace("http://spring.io/guides/gs-producing-web-service");
      wsdl11Definition.setSchema(cityRequestSchema);
      return wsdl11Definition;
   }

   @Bean
   public XsdSchema cityRequestSchema() {
      return new SimpleXsdSchema(new ClassPathResource("CityRequest.xsd"));
   }
}
Wait, I'm looking at the DefaultWsdl11Definition class, which I felt kind of weird, it doesn't seem sound right to me. Is it going to create the WSDL specification version 1.1, but my version is 1.2. I don't think this will work. Wait, the story has not ended, after a few days of searching, I manage to find a tutorial which has done a very good job on this matter. There are 2 ways to do this:

First solution
Do it in Spring configuration and load this configuration in the main class.
<beans xmlns="http://www.springframework.org/schema/beans" 
 xmlns:context="http://www.springframework.org/schema/context" 
 xmlns:jaxws="http://cxf.apache.org/jaxws" 
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
 xsi:schemalocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                     http://cxf.apache.org/jaxws http://cxf.apache.org/schemas/jaxws.xsd
                     http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">

   <context:component-scan base-package="org.huahsin68.core"/>

   <jaxws:endpoint 
      id="HelloService" 
      implementor="#helloResponseImpl"
      serviceName="s:HelloService"
      address="/hello"
      xmlns:s="http://huahsin68.org/helloService>
      <jaxws:features>
         < bean class="org.apache.cxf.ext.logging.LoggingFeature"/>
      </jaxws:features>
   </jaxws:endpoint> 
</beans>
@SpringBootApplication
@ImportResource({"classpath:beans.xml"})
public class Application {
   ...
   ...
}
Second solution
Do it in Java. Create an Endpoint bean inside the configuration bean.
@Configuration
public class WebServiceConfig {

   ...
   ...

   @Bean
   public Endpoint endpoint() {
      HelloService h = new HelloService();
      EndpointImpl endpoint = new EndpointImpl(springBus(), new InfoServiceImpl());

      endpoint.getFeatures().add(new LoggingFeature());
      endpoint.setWsdlLocation("classpath:hello.wsdl");
      endpoint.setServiceName(h.getServiceName());
      endpoint.publish("/hello");

      return endpoint;
   }
}

Reference:
Building soap web service with Apache CXF and Spring Boot

Friday, June 1, 2018

Maven unable to find valid certification path

Here is the most useful command that could help clean up the mess in Maven.
mvn –U clean compile
Unfortunately, that command is giving me a nasty error complaining that Maven was not able to find a valid certificate. WHAT THE HELL?
[ERROR] Plugin org.apache.maven.plugins:maven-compiler-plugin:3.7.0 or one of its dependencies could not be resolved: 
Failed to read artifact descriptor for org.apache.maven.plugins:maven-compiler-plugin:jar:3.7.0: Could not transfer artifact org.apache.maven.plugins:maven-plugins:pom:30 
from/to central (https://repo.maven.apache.org/maven2): sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: 
unable to find valid certification path to requested target -> [Help 1]
Will this error coming from the network firewall failure? If I read the details closely, this gives me a sense that my PC have not trusted the certificate for the site. In order to proceed the compilation, I must first trust the certificate, but how? I have no idea on dealing with Maven’s security issue during my past working experience. Spending hours on this issue and found this workaround from the Internet. First, follow the following steps to download the certificate and then import the certificate into a self-made keystore:
  1. Use a browser to go to https://repo.maven.apache.org/
  2. Click on lock icon and choose "View Certificate" 
  3. Go to the "Details"
  4. tab and choose "Save to File" Choose type "Base 64 X.509 (.CER)" and save it as mavenCert.cer 
  5. keytool -import -file mavenCert.cer -keystore mavenkeystore 
Once done, compile using following command:
mvn –U clean compile -Djavax.net.ssl.trustStore=mavenkeystore
From now on, whenever I need to download a new artifact from the maven repository or to do a clean build, I am required to use the command mention above instead of mvn –U clean compile.

Reference