-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathindex.xml
1641 lines (1308 loc) · 100 KB
/
index.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
<?xml version="1.0" encoding="utf-8" standalone="yes" ?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
<channel>
<title>VENISHJOE.NET</title>
<link>https://venishjoe.net/</link>
<description>Recent content on VENISHJOE.NET</description>
<generator>Hugo -- gohugo.io</generator>
<language>en-us</language>
<managingEditor>[email protected] (Venish Joe Clarence)</managingEditor>
<webMaster>[email protected] (Venish Joe Clarence)</webMaster>
<copyright>This work is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License.</copyright>
<lastBuildDate>Wed, 03 Jan 2018 10:00:00 -0500</lastBuildDate>
<atom:link href="https://venishjoe.net/index.xml" rel="self" type="application/rss+xml" />
<item>
<title>Places Visited Heatmap</title>
<link>https://venishjoe.net/post/places-visited-heatmap/</link>
<pubDate>Wed, 03 Jan 2018 10:00:00 -0500</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/places-visited-heatmap/</guid>
<description><p>I had a list of cities, addresses, landmarks etc. visited by me over the years and I was looking into ways to visualize those.
During my search, I came across <a href="https://developers.google.com/maps/documentation/javascript/heatmaplayer">Google Maps JavaScript API</a>
which not only visualizes location data but also has ways to show places which are visited more often than others.
But the API needs location data in a specific format with latitue and longitude coordinates in a JavaScript along with weightage for each.</p>
<p>This project is to convert my plain text cities, addresses, landmark etc. data to geographic coordinates and assign weightage to each location.
Once I have that, integrate the data with Google Maps to visualize.</p>
<p>Our end result will look like below. This is generated with a smaller set of test data.
Complete project is available in my Github <a href="https://github.com/venishjoe/places-visited-heatmap">places-visited-heatmap</a></p>
<p><img src="https://venishjoe.net/media/images/00012/places-visited-heatmap.png#floatcenter" alt="" /></p>
<p>Let&rsquo;s get started.</p>
<h5 id="google-api-keys">Google API Keys</h5>
<p>To start with, for both retrieving geographic coordinatesa nd visualizing data, we need free Google API Keys, actually two different keys as -
for Geo operations we need &ldquo;Google Geo API Key&rdquo; for retrieving geographic coordinates and &ldquo;Google API Key&rdquo; for visualizing. To get the keys, all
you need is a Google account.</p>
<p>&ldquo;Google Geo API Key&rdquo; - <a href="https://developers.google.com/maps/documentation/geocoding/get-api-key">developers.google.com/maps/documentation/geocoding/get-api-key</a></p>
<p>&ldquo;Google API Key&rdquo; - <a href="https://developers.google.com/maps/documentation/javascript/get-api-key">developers.google.com/maps/documentation/javascript/get-api-key</a></p>
<h5 id="convert-data">Convert Data</h5>
<p>Once you have API keys, we can get started with converting plain text data to geographic coordinates. I am using Go to implementing data transformation.</p>
<p>My input data is going to be a text file with location details. Something like below.</p>
<pre><code class="clean">Niagara Falls, NY
San Francisco, CA
Empire State Building, NY
Acadia National Park, Bar Harbour, ME
</code></pre>
<p>I open this file and start scanning using bufio. I also create two new output files - locationlatlng.data to write location data with geographic coordinates,
if you are just interested in only converting data and also places_data.js which will be a JavaScript file with location data which will be used by
Google Maps JavaScript API to visualize data.</p>
<pre><code class="golang">//Read Input File with Locations Data
fileWithLocationData, errReadingLocationData := os.Open("../data/location.data")
handleFatalError(errReadingLocationData)
fileWithLocationDataScanner := bufio.NewScanner(fileWithLocationData)
//Create file to write output delimited data
locationDataFileWithLatLng, errWritingFileWithLatLng := os.Create("../data/locationlatlng.data")
handleFatalError(errWritingFileWithLatLng)
//Create file to write output JS for Goolgle Maps Rendering
jsDataForHeatMap, errWritingJSDataForHeatMap := os.Create("../ui/places_data.js")
handleFatalError(errWritingJSDataForHeatMap)
</code></pre>
<p>Once the input location.data file is scanned, we can start reading line by line and process using Geocode API. We will be sending Google geo API key
along with the data from input file to the web service and process response JSON to retrieve data corresponding to input. To process JSON we
will use this excellent library <a href="https://github.com/tidwall/gjson">gjson</a> which helps in parsing response JSON.</p>
<p>From response JSON, we will be reading formatted_address, address_components which will be primarily used only for the output file and not for visualization
JavaScript. For visualization, we will be reading geometry.location.lat &amp; geometry.location.lng (which will also be written to output file)</p>
<pre><code class="golang">//Read Google API Key
googleAPIKey, errReadingAPIKey := ioutil.ReadFile("../data/googlegeoapi.key")
handleFatalError(errReadingAPIKey)
//Build Web Service URL
googleAPIBaseURL := "https://maps.googleapis.com/maps/api/geocode/json?key=" + string(googleAPIKey) + "&address="
//Call Web Service
googleAPIConstructedURL := googleAPIBaseURL + url.QueryEscape(fileWithLocationDataScanner.Text())
response, errFromAPI := httpClient.Get(googleAPIConstructedURL)
handleFatalError(errFromAPI)
responseBytes, errFromReadResponse := ioutil.ReadAll(response.Body)
responseString := string(responseBytes)
//Process response from service
formattedAddressArray := gjson.Get(responseString, "results.#.formatted_address")
for _, formattedAddress := range formattedAddressArray.Array() {
fmt.Fprintf(locationDataFileWithLatLng, formattedAddress.String()+"$")
addressComponentsArray := gjson.Get(responseString, "results."+strconv.Itoa(indexInner)+".address_components.#.short_name")
for _, addressComponentsArray := range addressComponentsArray.Array() {
fmt.Fprintf(locationDataFileWithLatLng, addressComponentsArray.String()+"$")
}
geometryLocationLat := gjson.Get(responseString, "results."+strconv.Itoa(indexInner)+".geometry.location.lat")
geometryLocationLng := gjson.Get(responseString, "results."+strconv.Itoa(indexInner)+".geometry.location.lng")
fmt.Fprintf(locationDataFileWithLatLng, geometryLocationLat.String()+"$"+geometryLocationLng.String()+"\n")
</code></pre>
<p>Now we have all the data we are looking for, we can start building JavaScript data for visualization. If you remember,
I was mentioning about assign weightage to each location on how frequent it appears in our input. Which basically means, if I
visited location A three times and location B one time, in the map we should show location A with high intensity. That&rsquo;s
done by assigning weight to every location.</p>
<p>Let&rsquo;s start by creating a struct to hold our data for visualization. We need latitude, longitude and weight.</p>
<pre><code class="golang">//LocationHeatMapData - Data structure to hold heat map data
type LocationHeatMapData struct {
Latitude, Longitude string
Weight float64
}
//LocationHeatMap - Data structure to hold LocationHeatMapData
type LocationHeatMap struct {
LocationHeatMap []LocationHeatMapData
}
</code></pre>
<p>Now, we have to start loading geographic coordinates data from response JSON to our LocationHeatMapData struct.
We will use a constant weight of 0.5 for every location we add. If same geographic coordinates already exists in
LocationHeatMapData, then we will increment weight by 0.1. So, more frequently visited places will have a higher
weightage compared to rest.</p>
<pre><code class="golang">if len(locationHeatMap.LocationHeatMap) == 0 {
locationHeatMap.LocationHeatMap = append(locationHeatMap.LocationHeatMap,
LocationHeatMapData{Latitude: geometryLocationLat.String(), Longitude: geometryLocationLng.String(), Weight: 0.5})
} else {
dataMatchIndex := checkIfValueExists(locationHeatMap, geometryLocationLat.String(), geometryLocationLng.String())
if dataMatchIndex != -1 {
locationHeatMap.LocationHeatMap[dataMatchIndex].Weight = locationHeatMap.LocationHeatMap[dataMatchIndex].Weight + 0.1
} else {
locationHeatMap.LocationHeatMap = append(locationHeatMap.LocationHeatMap,
LocationHeatMapData{Latitude: geometryLocationLat.String(), Longitude: geometryLocationLng.String(), Weight: 0.5})
}
}
</code></pre>
<p>To check for existing location in LocationHeatMapData struct we will use below function</p>
<pre><code class="golang">//Function to check if Latitue/Longitue exists in data structure
func checkIfValueExists(locationHeatMapCheck LocationHeatMap, geometryLocationLatCheck, geometryLocationLngCheck string) int {
for locationDataIndexCheck := 0; locationDataIndexCheck < len(locationHeatMapCheck.LocationHeatMap); locationDataIndexCheck++ {
if locationHeatMapCheck.LocationHeatMap[locationDataIndexCheck].Latitude == geometryLocationLatCheck &&
locationHeatMapCheck.LocationHeatMap[locationDataIndexCheck].Longitude == geometryLocationLngCheck {
return locationDataIndexCheck
}
}
return -1
}
</code></pre>
<p>Finally, we write all the data to places_data.js file under getDataPoints() function which will be used by visualization library in
next section</p>
<pre><code class="golang">fmt.Fprintf(jsDataForHeatMap, "function getDataPoints() { \n\treturn [\n")
for indexLocationDataWriteIndex := 0; indexLocationDataWriteIndex < len(locationHeatMap.LocationHeatMap); indexLocationDataWriteIndex++ {
fmt.Fprintf(jsDataForHeatMap, "\t\t{location: new google.maps.LatLng("+
locationHeatMap.LocationHeatMap[indexLocationDataWriteIndex].Latitude+", "+
locationHeatMap.LocationHeatMap[indexLocationDataWriteIndex].Longitude+"), weight: "+
strconv.FormatFloat(locationHeatMap.LocationHeatMap[indexLocationDataWriteIndex].Weight, 'f', 1, 64)+"}")
if indexLocationDataWriteIndex == len(locationHeatMap.LocationHeatMap)-1 {
fmt.Fprintf(jsDataForHeatMap, "\n")
} else {
fmt.Fprintf(jsDataForHeatMap, ",\n")
}
}
fmt.Fprintf(jsDataForHeatMap, "\t]; \n}")
</code></pre>
<h5 id="visualization">Visualization</h5>
<p>Now, we should have a JavaScript file (places_data.js) like below.</p>
<pre><code class="js">function getDataPoints() {
return [
{location: new google.maps.LatLng(36.1699412, -115.1398296), weight: 0.7},
{location: new google.maps.LatLng(43.0962143, -79.0377388), weight: 0.8},
...
{location: new google.maps.LatLng(32.715738, -117.1610838), weight: 0.5}
];
}
</code></pre>
<p>All we have to do now is to include this JavaScript in a HTML page which will load Google maps and load our location data as a
heatmap on the map. For loading Google maps for heatmap visualization, we need Google API Key (not same as Geo API Key)</p>
<pre><code class="html">&lt;script type=&quot;text/javascript&quot; src=&quot;places_data.js&quot;&gt;&lt;/script&gt;
&lt;script async defer src=&quot;https://maps.googleapis.com/maps/api/js?key=##YOUR_API_KEY_HERE##&amp;libraries=visualization&amp;callback=initMap&quot;&gt;&lt;/script&gt;
&lt;script&gt;
var map, heatmap;
function initMap() {
map = new google.maps.Map(document.getElementById('map'), {
zoom: 5,
center: {lat: 40.055347, lng: -101.030931},
mapTypeId: 'roadmap'
});
heatmap = new google.maps.visualization.HeatmapLayer({
data: getDataPoints(),
map: map
});
//Radius configuration
heatmap.set('radius', heatmap.get('radius') ? null : 20);
//Opacity configuration
heatmap.set('opacity', 0.8);
}
&lt;/script&gt;
</code></pre>
<p>Once we load this HTML in browser, it should produce something like below. There are lot of customizations which can be done on the map.
All configuration options are documented under <a href="https://developers.google.com/maps/documentation/javascript/tutorial">Google Documentation</a>.
Below screenshot is a vanilla render.</p>
<p><img src="https://venishjoe.net/media/images/00012/places-visited-heatmap.png#floatcenter" alt="" /></p>
<p>Full source code for all snippets referenced in this article is available in <a href="https://github.com/venishjoe/places-visited-heatmap">my github</a> page.</p>
<p></p></description>
</item>
<item>
<title>Java Bytecode Manipulation</title>
<link>https://venishjoe.net/post/java-bytecode-manipulation/</link>
<pubDate>Sun, 09 Apr 2017 01:40:22 -0500</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/java-bytecode-manipulation/</guid>
<description><p>In this article, I will show how to manipulate a compiled class file directly without decompiling it to java.</p>
<p>I will be using <a href="http://jboss-javassist.github.io/javassist/">Javassist (Java Programming Assistant)</a>, an external library for most of this tutorial.
<a href="https://github.com/jboss-javassist/javassist/zipball/master">Download</a> latest JAR file to get examples work. I am using version <em>rel_3_22_0_cr1-4-g6a3ed31</em>.</p>
<p>Every java file compiled will generate a class file which is a binary file containing Java bytecode which can be executed on any Java Virtual Machine.
Since the class files are generally not dependent on the platform they are compiled on, it makes Java applications platform independent.
In this article, we will explore how to statically analyze class files, modify them programmatically and execute.</p>
<h5 id="sample-class-for-bytecode-manipulation">Sample Class for Bytecode Manipulation</h5>
<p>We will start with a simple test class (ByteCodeEditorTest) which we will use to modify using Javassist. This class file will get an input from user and check if it matches
a predefined value within code and output message accordingly.</p>
<pre><code class="java">public String checkStatus(String _inputString){
if (_inputString.equals("MAGIC"))
return "Right!";
return "Wrong";
}
</code></pre>
<p>Once compiled, and executed below is a sample behaviour of the class. We will modify compiled class file directly to change its behaviour by modifying equality operator.</p>
<pre><code class="bash">$ java ByteCodeEditorTest TEST
Wrong
$ java ByteCodeEditorTest MAGIC
Right!
</code></pre>
<p>Let&rsquo;s start by looking at the compiled class file using javap. I have provided snippet of checkStatus() method from test class.</p>
<pre><code class="assembler">$ javap -c ByteCodeEditorTest
Compiled from "ByteCodeEditorTest.java"
public java.lang.String checkStatus(java.lang.String);
Code:
0: aload_1
1: ldc #7 // String MAGIC
3: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
6: ifeq 12
9: ldc #9 // String Right!
11: areturn
12: ldc #10 // String Wrong
14: areturn
}
</code></pre>
<p>The disassembled code contains mnemonic for Java bytecode instructions. We will be heavily using these as a part of bytecode manipulation.
Refer to <a href="https://en.wikipedia.org/wiki/Java_bytecode_instruction_listings">Java bytecode instruction listings</a> Wikipedia
article which contains all mnemonic and Opcode for Java bytecode.</p>
<p>Interesting line is on index 6 from disassembled code which contains mnemonic ifeq which compares input string against built in value.
Let&rsquo;s use Javassist to modify equality operator from ifeq to ifne.</p>
<h5 id="bytecode-manipulation-using-javassist">Bytecode Manipulation using Javassist</h5>
<p>Now that we have our test class and details on what has to be modified in bytecode, let&rsquo;s create a new class file which loads compiled ByteCodeEditorTest class
for manipulation. With Javassist JAR in classpath, let&rsquo;s load the test class file using javassist.CtClass.</p>
<pre><code class="java">ClassPool _classPool = ClassPool.getDefault();
CtClass _ctClass = _classPool.makeClass(new FileInputStream("ByteCodeEditorTest.class"));
</code></pre>
<p>Once ByteCodeEditorTest class is loaded, we will use javassist.CtMethod to extract all the methods from class and then use
javassist.bytecode.CodeAttribute &amp; javassist.bytecode.CodeIterator to manipulate the class.</p>
<p>CodeIterator allows us to traverse every bytecode instruction from class file and also provides methods to manipulate them. In our case,
from the javap output we know index 6 has to modified to change instruction set from ifeq to ifne. Looking at Opcode reference, hex value
for ifne is 9a. We will be using decimal format to update bytecode using CodeIterator.</p>
<p>So we will be using CodeIterator.writeByte() method to update index 6 of ByteCodeEditorTest from exising value to 154 (9a converted to decimal).
Below table shows existing value (row1) and new value (row2)</p>
<table>
<thead>
<tr>
<th>Mnemonic</th>
<th>Opcode (Hex)</th>
<th>Opcode (Decimal)</th>
</tr>
</thead>
<tbody>
<tr>
<td>ifeq</td>
<td>0x99</td>
<td>153</td>
</tr>
<tr>
<td>ifne</td>
<td>0x9a</td>
<td>154</td>
</tr>
</tbody>
</table>
<pre><code class="java">for(CtMethod _ctMethods:_ctClass.getDeclaredMethods()){
CodeAttribute _codeAttribute = _ctMethods.getMethodInfo().getCodeAttribute();
CodeIterator _codeIterator = _codeAttribute.iterator();
while (_codeIterator.hasNext()) {
int _indexOfCode = _codeIterator.next();
int _valueOfIndex8Bit = _codeIterator.byteAt(_indexOfCode);
//Checking index 6 and if Opcode is ifeq
if(_valueOfIndex8Bit==153 && _indexOfCode==6) {
//Changing instruction from ifeq to ifne
_codeIterator.writeByte(154, _indexOfCode);
}
}
}
//Write changes to class file
_ctClass.writeFile();
</code></pre>
<p>Once this code is run, ByteCodeEditorTest class file will be modified with updated instructions.
When running javap on ByteCodeEditorTest now, it will produce below result of checkStatus() method.</p>
<pre><code class="assembler">$ javap -c ByteCodeEditorTest
Compiled from "ByteCodeEditorTest.java"
public java.lang.String checkStatus(java.lang.String);
Code:
0: aload_1
1: ldc #7 // String MAGIC
3: invokevirtual #8 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
6: ifne 12
9: ldc #9 // String Right!
11: areturn
12: ldc #10 // String Wrong
14: areturn
}
</code></pre>
<p>As you can see, index 6 is now changed to ifne. Running ByteCodeEditorTest now will produce results which we were after.</p>
<pre><code class="bash">$ java ByteCodeEditorTest TEST
Right!
</code></pre>
<p>ByteCodeEditorTest class file was successfully modified to alter program flow without the need for re-compilation or decompilation.</p>
<p>While this is a simple modification to a class file, we can do complex changes of adding new methods, classes, injecting code etc. using
Javassist library. I will cover complex scenarios in another article, but will give a high level overview of frequently used in
APIs in next section.</p>
<h5 id="other-javassist-apis">Other Javassist APIs</h5>
<p>While I covered bytecode manipulation, Javassist is a powerful library which can be used for complex changes. Highlighting some of those features here.</p>
<p>javassist.CtMethod class can be used to inject new methods to existing class files.</p>
<pre><code class="java">//Defrosts so that the class can be modified
_ctClass.defrost();
CtMethod _ctMethod = CtNewMethod.make("public int newMethodFromJA() { return 1; }", _ctClass);
_ctClass.writeFile();
</code></pre>
<p>javassist.CtMethod class can also be used to inject code to existing class/methods using insertBefore(), insertAfter() and insertAt() methods.</p>
<pre><code class="java">for(CtMethod method:_ctClass.getDeclaredMethods()){
//Defrosts so that the class can be modified
_ctClass.defrost();
method.insertBefore("System.out.println(\"Before every method call....\");");
_ctClass.writeFile();
}
</code></pre>
<p>Javassist can also be used for static analysis of class files by displaying all method code (disassembled) of a class file or to display bytecode of a class file.</p>
<pre><code class="java">//Display Method Code
PrintStream _printStream = new PrintStream(System.out);
InstructionPrinter instructionPrinter = new InstructionPrinter(_printStream);
for(CtMethod method:_ctClass.getDeclaredMethods()){
System.out.println("Method: " + method.getName());
instructionPrinter.print(method);
}
//Display Bytecode
for(CtMethod _ctMethods:_ctClass.getDeclaredMethods()){
_ctClass.defrost();
System.out.println("Method: " +_ctMethods.getName());
CodeAttribute _codeAttribute = _ctMethods.getMethodInfo().getCodeAttribute();
CodeIterator _codeIterator = _codeAttribute.iterator();
while (_codeIterator.hasNext()) {
int _indexOfInstruction = _codeIterator.next();
int _indexValue8Bit = _codeIterator.byteAt(_indexOfInstruction);
System.out.println(Mnemonic.OPCODE[_indexValue8Bit]);
}
}
</code></pre>
<p>Full source code for all snippets referenced in this article is available in <a href="https://github.com/venishjoe/blog-code/tree/master/bytecode-manipulation">my github</a> page.</p>
<p></p></description>
</item>
<item>
<title>Dynamic Columns in JSP Model with Struts Framework</title>
<link>https://venishjoe.net/post/dynamic-columns-in-jsp-model-with-struts/</link>
<pubDate>Sun, 18 Apr 2010 21:41:00 +0000</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/dynamic-columns-in-jsp-model-with-struts/</guid>
<description><p>While developing web applications, we will come across a lot of scenarios where we should use dynamic columns depending on the entitlement of the user or
from the result set depending on the data itself. Dynamic columns in web applications give control to the user on what he wants to see
(specially when we have a huge amount of data to work with). For applications with sensitive data,
this can be even extended to act as a security layer where the access to specific data can be controlled with high precision.</p>
<p>In this article, I will explain one of the methods to implement this in any J2EE application with little or no code change.</p>
<h5 id="high-level-architecture">High Level Architecture</h5>
<p><img src="https://venishjoe.net/media/images/00010/dynamic-columns-in-jsp-model-with-struts.png#floatcenter" alt="" /></p>
<p>In a nut shell, this design uses the Application Context of the container to maintain the values pertaining to a particular user,
if the requirement demands not to maintain the preference after a user session is terminated, then it can be achieved by destroying the object stored in the context.</p>
<p>We will start by creating a singleton class, which will be used to store the user preference about the columns.
The user preference object can be mapped against the user id or any other primary key, so that different preferences are maintained for different users.
While the container starts, the instance for the singleton will be created. The default preferences can be loaded from a property / xml file or from a data store (DB).
This object will contain the preferences of different pages with the different key names so that the same object can be used to maintain the preference across the application.
This will be read during the logon operation and if the object in the application context doesn&rsquo;t contain any values
(if the user logs in for the first time or in an application where the preference is specific to the session) then the default values are loaded. Once the page loads,
the preference can be read from the application context and can be presented to the user. If the user edits his preferences, it will be updated in the application context.
Note that the application context is not persistent between container restarts, so appropriate mechanisms should be taken to store the data.</p>
<h5 id="implementation">Implementation</h5>
<p>Let’s go through the implementation now. The following steps describe how to integrate this component to an existing Struts application.</p>
<h6 id="start-up-servlet-and-initializing-the-singleton-class">Start-up servlet and initializing the Singleton Class</h6>
<p>Create an Initializer Servlet and make an entry for the same in the web.xml file so that the Servlet starts when the container is initialized.
Make sure the load-on-startup is set to 1, which ensures that the application server loads the servlet while startup.</p>
<pre><code class="xmls">&lt;servlet&gt;
&lt;servlet-name&gt; InitializerServlet &lt;/servlet-name&gt;
&lt;servlet-class&gt;com.startup.common.InitializerServlet&lt;/servlet-class&gt;
&lt;load-on-startup&gt; 1 &lt;/load-on-startup&gt;
&lt;/servlet&gt;
</code></pre>
<p>Next, create a Singleton class, which contains getter and setter methods for dynamic column preference, the object can be any collection,
we are using Hash Map in this example which will be used to store the primary key against the list containing the preference.
The set &amp; get methods in the Singleton should be synchronized so that the simultaneous access is restricted. Also override the clone() method in your singleton.</p>
<pre><code class="java">public class AppSingleton implements Serializable {
private Hashtable cusomizeViewValues = null;
private static AppSingleton appSingleton = null;
private AppSingleton (){ }
public synchronized void setCusomizeViewValues (Hashtable cusomizeViewValues){
this.cusomizeViewValues = cusomizeViewValues;
}
public static synchronized AppSingleton getInstance () throws Exception {
try {
if (appSingleton == null)
return new AppSingleton ();
} catch (Exception e) {
throw new Exception();
}
}
public Object clone() throws CloneNotSupportedException{
throw new CloneNotSupportedException();
}
}
</code></pre>
<p>In the startup servlet, create an instance of the singleton class. When created, the object will be available in the application context of the container,
and no one will be able to create another instance, until the object created in startup is destroyed.
Since we have overridden the clone method, no one will be able to clone the particular object.
These measures are to ensure the integrity of the user preference stored in the singleton.
A sample Initializer servlet will look like the following code.</p>
<pre><code class="java">public class InitializerServlet extends HttpServlet {
public void init () throws ServletException {
AppSingleton appSingleton = AppSingleton.getInstance ();
}
public void destroy (){}
public void service (HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {}
}
</code></pre>
<p>Now, create a Data Transfer Object (DTO) / Value Object (VO) for storing the values.
The VO/DTO will contain just two getters and setters, one for the Column Display name and the other for the bean property. This will be a POJO.</p>
<h6 id="populate-the-application-context">Populate the Application context</h6>
<p>When the container starts, populate the list in the application context, from the property file or from the data source.
If you are having a separate page to choose the columns displayed, you can use the same list to render the values initially.
Similarly if the user has changed his preference then update the application context accordingly.
This can be done during the Login Action, once the user is authorized and authenticated.
You can use your own logic to get all the user preference and then update list with DTO’s/VO’s containing the display name and the property name.
This list is updated in the application context against the primary key.
Before updating the application context check if the PK is already present in the Hash Table if yes, update or create a new entry.</p>
<p>A sample property file will look like the one given below. By using different keys, we can have entries for different pages.
Also the columns to be displayed to the user irrespective of the individual preference can also be marked here under a different key.
The columns users are not allowed to modify are added to the rendering list once the request is got from the particular page and not during the logon time.
The values are appended to the modifiable columns list and rendered to the user.</p>
<pre><code class="properties">Validations$Optional=Plan #, Plan Name, Administrator
Validations$Core= Plan Val Description, Plan Val Status
# Optional represents the Columns users can modify
# Core represents the Columns users can’t modify
Validations$Plan#=strClientExtEntityId
Validations$PlanName=strPlanName
Validations$Administrator=strAdministrator
Validations$PlanValDescription=strDescription
Validations$PlanValStatus=strStatus
</code></pre>
<h6 id="rendering-logic">Rendering Logic</h6>
<p>Once the values are available in the session, using JSP, logic iterate, render the Column names.
Then to display the values from the result set, use the logic iterate with the list containing the values for the page,
which is used to render the &lt;tr&gt; tag and inside that logic iterate, use another logic iterate,
which is used to render the columns and use a bean define tag to get the column name properties in a scriplet variable and then use a bean define tag to display the value of the property.
This logic is highly dynamic.</p>
<p>To display the column names,</p>
<pre><code class="jsp">&lt;logic:iterate name="&lt;Form Bean Name&gt;" id="testId" property="&lt;Name of the List&gt;" &gt;
&lt;td&gt;
&lt;bean:write name=" testId " property="&lt;Col Disp Name&gt;"/&gt;
&lt;/td&gt;
&lt;/logic:iterate&gt;
</code></pre>
<p>To display the result set,</p>
<pre><code class="jsp">&lt;logic:iterate name="&lt;Form Name&gt;" id="outerId" property="&lt;Property of the Hitlist&gt;"&gt;
&lt;tr&gt;
&lt;logic:iterate name="&lt;Form Name&gt;" id="innerId" property="&lt;Name of the List&gt;" &gt;
&lt;bean:define name="innerId" id="propId" property="&lt;Col Property&gt;" type="String"/&gt;
&lt;td&gt;
&lt;bean:write name="outerId" property="&lt;%= propId %&gt;" /&gt;
&lt;/td&gt;
&lt;/logic:iterate&gt;
&lt;/tr&gt;
&lt;/logic:iterate&gt;
</code></pre>
<p>We also will have situations to display hyperlinks, textboxes etc. in the result set, the same logic can be used to display the different objects in the JSP.
Just before the bean write tag, have a logic equal tag to check for specific types and render the display.</p>
<p>This architecture is highly customizable and can be easily plugged in into any existing J2EE application. Also this can be easily enhanced to incorporate new functionalities.</p>
<p></p></description>
</item>
<item>
<title>Java String Concatenation and Performance</title>
<link>https://venishjoe.net/post/java-string-concatenation-and-performance/</link>
<pubDate>Sun, 08 Nov 2009 18:01:00 +0000</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/java-string-concatenation-and-performance/</guid>
<description><p>The quick and dirty way to concatenate strings in Java is to use the concatenation operator (+).
This will yield a reasonable performance if you need to combine two or three strings (fixed-size).
But if you want to concatenate n strings in a loop, the performance degrades in multiples of n.
Given that String is immutable, for large number of string concatenation operations, using (+) will give us a worst performance.
But how bad ? How StringBuffer, StringBuilder or String.concat() performs if we put them on a performance test ?.
This article will try to answer those questions.</p>
<p>We will be using <a href="https://github.com/perf4j/perf4j">Perf4J</a> to calculate the performance, since this library will give us aggregated performance statistics
like mean, minimum, maximum, standard deviation over a set time span. In the code, we will concatenate a string (*)
repeatedly 50,000 times and this iteration will be performed 21 times so that we can get a good standard deviation.
The following methods will be used to concatenate strings.</p>
<ul>
<li>Concatenation Operator (+)</li>
<li><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/String.html#concat%28java.lang.String%29">String concat method</a> - concat(String str)</li>
<li><a href="http://java.sun.com/j2se/1.4.2/docs/api/java/lang/StringBuffer.html#append%28java.lang.String%29">StringBuffer append method</a> - append(String str)</li>
<li><a href="http://java.sun.com/j2se/1.5.0/docs/api/java/lang/StringBuilder.html#append%28java.lang.String%29">StringBuilder append method</a> - append(String str)</li>
</ul>
<p>And finally we will look at the byte code to see how each of these operations perform. Let’s start building the class.
Note that each of the block in the code should be wrapped around the Perf4J library to calculate the performance in each iteration.
Let’s define the outer and inner iterations first.</p>
<pre><code class="java">private static final int OUTER_ITERATION=20;
private static final int INNER_ITERATION=50000;
</code></pre>
<p>Now let’s implement each of the four methods mentioned in the article.
Nothing fancy here, plain implementations of (+), String.concat(), StringBuffer.append() &amp; StringBuilder.append().</p>
<pre><code class="java">String addTestStr = "";
String concatTestStr = "";
StringBuffer concatTestSb = null;
StringBuilder concatTestSbu = null;
for (int outerIndex=0;outerIndex&lt;=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringAddConcat");
addTestStr = "";
for (int innerIndex=0;innerIndex&lt;=INNER_ITERATION;innerIndex++)
addTestStr += "*";
stopWatch.stop();
}
for (int outerIndex=0;outerIndex&lt;=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringConcat");
concatTestStr = "";
for (int innerIndex=0;innerIndex&lt;=INNER_ITERATION;innerIndex++)
concatTestStr = concatTestStr.concat("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex&lt;=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBufferConcat");
concatTestSb = new StringBuffer();
for (int innerIndex=0;innerIndex&lt;=INNER_ITERATION;innerIndex++)
concatTestSb.append("*");
stopWatch.stop();
}
for (int outerIndex=0;outerIndex&lt;=OUTER_ITERATION;outerIndex++) {
StopWatch stopWatch = new LoggingStopWatch("StringBuilderConcat");
concatTestSbu = new StringBuilder();
for (int innerIndex=0;innerIndex&lt;=INNER_ITERATION;innerIndex++)
concatTestSbu.append("*");
stopWatch.stop();
}
</code></pre>
<p>Let’s run this program and generate the performance metrics. I ran this program in a 64-bit OS (Windows 7), 32-bit JVM (7-ea), Core 2 Quad CPU (2.00 GHz) with 4 GB RAM.</p>
<p>The output from the 21 iterations of the program is plotted below.</p>
<p><img src="https://venishjoe.net/media/images/00009/java-string-concatenation-and-performance.png#floatcenter" alt="" /></p>
<p>Well, the results are pretty conclusive and as expected. One interesting point to notice is how better String.concat performs.
We all know String is immutable, then how the performance of concat is better. To answer the question we should look at the byte code.
I have included the whole byte code in the download package, but let’s have a look at the below snippet.</p>
<pre><code class="bytecode">45: new #7; //class java/lang/StringBuilder
48: dup
49: invokespecial #8; //Method java/lang/StringBuilder."&lt;init&gt;":()V
52: aload_1
53: invokevirtual #9; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
56: ldc #10; //String *
58: invokevirtual #9; //Method java/lang/StringBuilder.append:
(Ljava/lang/String;)Ljava/lang/StringBuilder;
61: invokevirtual #11; //Method java/lang/StringBuilder.toString:()
Ljava/lang/String;
64: astore_1
</code></pre>
<p>This is the byte code for String.concat(), and its clear from this that the String.concat is using StringBuilder for concatenation and the performance should be as good as String Builder.
But given that the source object being used is String, we do have some performance loss in String.concat.</p>
<p>So for the simple operations we should use String.concat compared to (+), if we don’t want to create a new instance of StringBuffer/Builder.
But for huge operations, we shouldn’t be using the concat operator, as seen in the performance results it will bring down the application to its knees and spike up the CPU utilization.
To have the best performance, the clear choice is StringBuilder as long as you do not need thread-safety or synchronization.</p>
<p>Full source of this application is available in <a href="https://github.com/venishjoe/blog-code/tree/master/string-concatenation-perf">my github</a> page.</p>
<p></p></description>
</item>
<item>
<title>Recursive File Tree Traversing in Java using NIO.2</title>
<link>https://venishjoe.net/post/recursive-file-tree-traversing-in-java-using-nio/</link>
<pubDate>Mon, 26 Oct 2009 11:45:00 +0000</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/recursive-file-tree-traversing-in-java-using-nio/</guid>
<description><p>In my <a href="https://venishjoe.net/post/monitor-a-directory-for-changes-using-java/">previous article about NIO.2</a>,
we have seen how to implement a service which monitors a directory recursively for any changes.
In this article we will look at another improvement in JDK7 (NIO.2) called FileWatcher.
This will allow us to implement a search or index. For example, we can find all the $some_pattern$ files in a given directory recursively and (or)
delete / copy all the all the $some_pattern$ files in a file system.
In a nutshell FileWatcher will get us a list of files from a file system based on a pattern which can be processed based on our requirement.</p>
<p>The FileVistor is an interface and our class should implement it.
We have two methods before the traversal starts at the directory level &amp; file level, and one method after the traversal is complete,
which can be used for clean up or post processing. The important points from the interface is given in the below diagram.</p>
<p><img src="https://venishjoe.net/media/images/00008/recursive-file-tree-traversing-class-diagram.png#floatcenter" alt="" /></p>
<p>While I think FileVistor is the best way to handle this, JDK7 NIO.2 has given another option to achieve the same, a class named SimpleFileVistor (which implements FileVisitor).
It should be self explanatory, a simplified version of FileVisitor.
We can extend the SimpileFileVisitor into our class and then traverse the directory with overriding only the methods we need, and if any step fails we will get an IOException.</p>
<p>According to me, FileVisitor is better because it forces you to implement the methods (sure, you can leave them blank)
since these methods are really important if you plan to implement recursive delete / copy or work with symbolic links.
For example, if you are copying some files to a directory you should make sure that the directory should be created
first before copying which can be done in the preVisitDirectory().</p>
<p>The other area of concern is symbolic links and how this will be handled by FileVisitor. This can be achieved using FileVisitOption enums.
By default, the symbolic links are not followed so that we are not accidentally deleting any directories in a recursive delete.
If you want to handle manually, there are two options FOLLOW_LINKS (follow the links) &amp; DETECT_CYCLES (catch circular references).</p>
<p>If you want to exclude some directory from FileVisitor or if you are looking for a directory or a file in the file system and once you find it
you want to stop searching that can be implemented by using the return type of FileVisitor, called FileVisitResult.
SKIP_SUBTREE allows us to skip directories &amp; subdirectories. TERMINATE stops the traversing.</p>
<p>The search can be initiated by the walkFileTree() method in Files class. This will take the starting directory (or root directory in your search) as a parameter.
You can also define Integer.MAX_VALUE if you want to manually specify the depth.
And as mentioned in the above diagram, define FileVisitOption for symbolic links if needed.</p>
<p>Enough with the API description, let&rsquo;s write some sample code to implement what we discussed.
We will be using the SimpleFileVisitor so that in our demo we don’t need to implement all the methods.</p>
<p>Let’s start with defining the pattern which needs to be searched for. In this example,
we will search for all the *txt file / directory names recursively in any given directory.
This can be done with getPathMatcher() in FileSystems</p>
<pre><code class="java">PathMatcher pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + "*txt*");
</code></pre>
<p>Now, let’s initiate the search by calling walkFileTree() as mentioned below. We are not defining anything specific for symbolic links so, by default its NO_FOLLOW.</p>
<pre><code class="java">Files.walkFileTree(Paths.get("D://Search"), fileVisitor);
</code></pre>
<p>Let’s go through the implementations of class SimpleFileVisitor, we will be overriding only visitFile() &amp; preVisitDirectory() in this example,
but its a good practice to override all the five methods so that we have more control over the search. The implementation is pretty simple,
based on the pattern the below methods will search for a directory or file and print the path.</p>
<pre><code class="java">@Override
public FileVisitResult visitFile(Path filePath, BasicFileAttributes basicFileAttributes) {
if (filePath.getName() != null &amp;&amp; pathMatcher.matches(filePath.getName()))
System.out.println("FILE: " + filePath);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path directoryPath) {
if (directoryPath.getName() != null &amp;&amp; pathMatcher.matches(directoryPath.getName()))
System.out.println("DIR: " + directoryPath);
return FileVisitResult.CONTINUE;
}
</code></pre>
<p>Once this is completed, we can use the postVisitDirectory() to perform additional tasks or any cleanup if needed. A sample output from my machine is given below.</p>
<p><img src="https://venishjoe.net/media/images/00008/recursive-file-tree-traversing-output.png#floatcenter" alt="" /></p>
<p>The complete source code is given below. Please note that you need JDK7 to run this code.
Source is also available in <a href="https://github.com/venishjoe/blog-code/tree/master/jsr203-nio2_file-visitor">my github</a> page.</p>
<pre><code class="java">public class NIO2_FileVisitor extends SimpleFileVisitor&lt;Path&gt; {
private PathMatcher pathMatcher;
@Override
public FileVisitResult visitFile(Path filePath, BasicFileAttributes basicFileAttributes) {
if (filePath.getName() != null &amp;&amp; pathMatcher.matches(filePath.getName()))
System.out.println("FILE: " + filePath);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult preVisitDirectory(Path directoryPath) {
if (directoryPath.getName() != null &amp;&amp; pathMatcher.matches(directoryPath.getName()))
System.out.println("DIR: " + directoryPath);
return FileVisitResult.CONTINUE;
}
public static void main(String[] args) throws IOException {
NIO2_FileVisitor fileVisitor = new NIO2_FileVisitor();
fileVisitor.pathMatcher = FileSystems.getDefault().getPathMatcher("glob:" + "*txt*");
Files.walkFileTree(Paths.get("D://Search"), fileVisitor);
}
}
</code></pre>
<p></p></description>
</item>
<item>
<title>Dynamically Load Compiled Java Class as a Byte Array and Execute</title>
<link>https://venishjoe.net/post/dynamically-load-compiled-java-class/</link>
<pubDate>Wed, 21 Oct 2009 21:20:00 +0000</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/dynamically-load-compiled-java-class/</guid>
<description><p>As we know, all the compiled java classes runs inside the JVM. The default class loader from Sun loads the classes into JVM and executes it.
This class loader is a part of JVM which loads the compiled byte code to memory. In this article,
I will show how to convert a compiled java class to a array of bytes and then load these array of bytes into another class
(which can be over the network) and execute the array of bytes.</p>
<p>So the question arises, why should we write a custom class loader ? There are some distinct advantages. Some of them below</p>
<ul>
<li>We can load a class over any network protocol. Since the java class can be converted to a series of numbers (array of bytes), we can use most of the protocols.</li>
<li>Load Dynamic classes based on the type of user, especially useful when you want to validate the license of your software over the web and if you are paranoid about the security.</li>
<li>More flexible and secure, you can encrypt the byte stream (asymmetric or symmetric) ensuring safer delivery.</li>
</ul>
<p>For this article we will be creating three classes</p>
<ol>
<li>JavaClassLoader – The custom class loader which will load the array of bytes and execute. In other words, the client program.</li>
<li>Class2Byte – The Java class which converts any compiled class / object to a array of bytes</li>
<li>ClassLoaderInput – The class which will be converted to array of bytes and transferred</li>
</ol>
<p>Let’s divide this article into two sections, in the fist section we will convert the java class to array of bytes and in the second section, we will load that array.</p>
<h5 id="create-convert-the-java-class-to-array-of-bytes">Create &amp; Convert the Java class to array of bytes</h5>
<p>Let’s write a simple class (ClassLoaderInput) which just prints a line. This is the class which will be converted to a byte array.</p>
<pre><code class="java">public class ClassLoaderInput {
public void printString() {
System.out.println("Hello World!");
}
}
</code></pre>
<p>Now, let’s write another class (Class2Byte) which will convert the ClassLoaderInput to a byte of array.
The concept to convert the file is simple, compile the above file and load the class file through input stream and with an offset
read and convert the class to bytes and write the output in to another out stream.
We need these bytes as a comma separated value, so we will use StringBuffer to add comma between the bytes.</p>
<pre><code class="java">int _offset=0;
int _read=0;
File fileName = new File(args [0]);
InputStream fileInputStream = new FileInputStream(fileName);
FileOutputStream fileOutputStream = new FileOutputStream(args[1]);
PrintStream printStream = new PrintStream(fileOutputStream);
StringBuffer bytesStringBuffer = new StringBuffer();
byte[] byteArray = new byte[(int)fileName.length()];
while (_offset &lt; byteArray.length &amp;&amp;
(_read=fileInputStream.read(byteArray, _offset,
byteArray.length-_offset)) &gt;= 0)
_offset += _read;
fileInputStream.close();
for (int index = 0; index &lt; byteArray.length; index++)
bytesStringBuffer.append(byteArray[index]+",");
printStream.print(bytesStringBuffer.length()==0 ? "" :
bytesStringBuffer.substring(0, bytesStringBuffer.length()-1));
</code></pre>
<p>Now let’s run this file and generate the output. A sample output from my machine is below.</p>
<p><img src="https://venishjoe.net/media/images/00007/dynamically-load-compiled-java-class-output.png#floatcenter" alt="" /></p>
<p>Now,we have the sample class (ClassLoaderInput) file as a bunch of numbers. Now this bunch of numbers can be transferred over any protocol to our
custom class loader which will “reconstruct” the class from these bytes and run it,
without any physical trace in the client machine (the array of bytes will be on memory).</p>
<h5 id="load-the-array-of-bytes-and-execute">Load the array of bytes and execute</h5>
<p>Now, to the important part of this article, we are going to write a custom class loader which will load those bunch of numbers (array) and execute them.
The array of bytes can be transferred over the network but in this example, we will define it as a string in the class loader for demonstration purpose.</p>
<p>Let’s start by defining the array of bytes.</p>
<pre><code class="java">private int[] data = {-54,-2,-70,-66,0,0,0,51,0,31,10,0,6,0,17,9,0,18,0,19,8,
0,20,10,0,21,0,22,7,0,23,7,0,24,1,0,6,60,105,110,105,116,62,1,0,3,40,41,86,1,
0,4,67,111,100,101,1,0,15,76,105,110,101,78,117,109,98,101,114,84,97,98,108,
101,1,0,18,76,111,99,97,108,86,97,114,105,97,98,108,101,84,97,98,108,101,1,0,
4,116,104,105,115,1,0,18,76,67,108,97,115,115,76,111,97,100,101,114,73,110,
112,117,116,59,1,0,11,112,114,105,110,116,83,116,114,105,110,103,1,0,10,83,
111,117,114,99,101,70,105,108,101,1,0,21,67,108,97,115,115,76,111,97,100,101,
114,73,110,112,117,116,46,106,97,118,97,12,0,7,0,8,7,0,25,12,0,26,0,27,1,0,
12,72,101,108,108,111,32,87,111,114,108,100,33,7,0,28,12,0,29,0,30,1,0,16,67,
108,97,115,115,76,111,97,100,101,114,73,110,112,117,116,1,0,16,106,97,118,97,
47,108,97,110,103,47,79,98,106,101,99,116,1,0,16,106,97,118,97,47,108,97,110,
103,47,83,121,115,116,101,109,1,0,3,111,117,116,1,0,21,76,106,97,118,97,47,105,
111,47,80,114,105,110,116,83,116,114,101,97,109,59,1,0,19,106,97,118,97,47,105,
111,47,80,114,105,110,116,83,116,114,101,97,109,1,0,7,112,114,105,110,116,108,
110,1,0,21,40,76,106,97,118,97,47,108,97,110,103,47,83,116,114,105,110,103,59,
41,86,0,33,0,5,0,6,0,0,0,0,0,2,0,1,0,7,0,8,0,1,0,9,0,0,0,47,0,1,0,1,0,0,0,5,42,
-73,0,1,-79,0,0,0,2,0,10,0,0,0,6,0,1,0,0,0,1,0,11,0,0,0,12,0,1,0,0,0,5,0,12,0,
13,0,0,0,1,0,14,0,8,0,1,0,9,0,0,0,55,0,2,0,1,0,0,0,9,-78,0,2,18,3,-74,0,4,-79,
0,0,0,2,0,10,0,0,0,10,0,2,0,0,0,3,0,8,0,4,0,11,0,0,0,12,0,1,0,0,0,9,0,12,0,13,
0,0,0,1,0,15,0,0,0,2,0,16};
</code></pre>
<p>The conversion of these bytes to class is done by the <a href="http://java.sun.com/j2se/1.3/docs/api/java/lang/ClassLoader.html#defineClass%28byte[],%20int,%20int%29">ClassLoader.defineClass()</a>
method We should supply the stream of bytes that make up the class data.
The bytes in positions off through off+len-1 should have the format of a valid class file as defined by the <a href="http://java.sun.com/docs/books/vmspec/">Java Virtual Machine Specification</a>.
The offset and length will be the additional parameters. Once the defineClass converts the array to class,
then we can use reflection to execute the methods in the class.</p>
<pre><code class="java">JavaClassLoader _classLoader = new JavaClassLoader();
byte[] rawBytes = new byte[_classLoader.data.length];
for (int index = 0; index &lt; rawBytes.length; index++)
rawBytes[index] = (byte) _classLoader.data[index];
Class regeneratedClass = _classLoader.defineClass(args[0],
rawBytes, 0, rawBytes.length);
regeneratedClass.getMethod(args[1], null).invoke(null, new Object[] { args });
</code></pre>
<p>Now, let’s compile the class loader and run. The the class file name &amp; method name should be passed as a run time argument.
If you have done everything right, you should see the output from the input class which we created (ClassLoaderInput) initially.
Sample output from my machine below.</p>
<p><img src="https://venishjoe.net/media/images/00007/dynamically-load-compiled-java-class-output-patched.png#floatcenter" alt="" /></p>
<p>Full source of this application is available in <a href="https://github.com/venishjoe/blog-code/tree/master/dynamic-byte-class-array">my github</a> page.</p>
<p></p></description>
</item>
<item>
<title>Monitor a Directory for Changes using Java</title>
<link>https://venishjoe.net/post/monitor-a-directory-for-changes-using-java/</link>
<pubDate>Sun, 18 Oct 2009 02:23:00 +0000</pubDate>
<author>[email protected] (Venish Joe Clarence)</author>
<guid>https://venishjoe.net/post/monitor-a-directory-for-changes-using-java/</guid>
<description><p>Many applications which we use on a day to day basis like a music organizer, file editors monitor the directory for any changes in the files/directories and
take appropriate action in the application if there are any changes detected on the fly.
Since Java do not have direct access to the system level calls (unless we use JNI, which will make the code platform specific)
the only way to monitor any directory is to use a separate thread which will be using a lot of resources (memory &amp; disk I/O) to monitor the changes inside the directory.
If we have sub-directories and need a recursive monitor, then the thread becomes more resource intensive.</p>
<p>There was a JSR (Java Specification Request) requested to add / rewrite more I/O APIs for Java platform. This was implemented in JDK 7 as
<a href="http://jcp.org/en/jsr/detail?id=203">JSR 203</a> with support for APIs like file system access, scalable asynchronous I/O operations,
socket-channel binding and configuration, and multicast datagrams.</p>
<p>JSR 203 is one of the big feature for JDK 7 (Developer Preview is available in java.sun.com) and its been implemented as the second I/O package is java,
called as NIO.2. I will be looking into more of these packages in future posts, but in this,
I will show how to monitor a directory and its sub-directories for any changes using NIO.2 (JDK 7).</p>
<p>The APIs which we will be using <a href="http://java.sun.com/javase/7/docs/api/java/nio/file/WatchService.html">WatchService</a>
(a watch service that watches registered objects for changes and events), <a href="http://java.sun.com/javase/7/docs/api/java/nio/file/WatchKey.html">WatchKey</a>
(a token representing the registration of a watchable object with a WatchService) and <a href="http://java.sun.com/javase/7/docs/api/java/nio/file/WatchEvent.html">WatchEvent</a>
(an event or a repeated event for an object that is registered with a WatchService) to monitor a directory. So, without further explanation, let’s start working on the code.</p>
<p>Please note that you need JDK 7 to run this program. While writing this post,
JDK 7 is available as a EA (Early Access) in <a href="http://java.sun.com/javase/downloads/ea.jsp">Java Early Access Downloads</a> page. Download the JDK and install it.</p>
<p>The first step is to get a directory to monitor. Path is one of the new I/O API as a part of NIO.2 which gives us more control over the I/O.
So let’s get the directory to watch, if you want to watch the directory recursively then there should be another boolean flag defined,
but in this example we will watch only the parent directory.</p>
<pre><code class="java">Path _directotyToWatch = Paths.get(args[0]);
</code></pre>
<p>Now let’s create a Watch service to the above directory and add a key to the service.
In the watch key we can define what are all the events we need to look for.
In this example we will monitor Create, Delete &amp; Rename/Modify of the files or directories in the path.</p>
<pre><code class="java">WatchService watcherSvc = FileSystems.getDefault().newWatchService();
WatchKey watchKey = _directotyToWatch.register(
watcherSvc,ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY);
</code></pre>
<p>Now we have all the variables defined. Let’s start a infinite loop to monitor the directory for any changes using WatchEvent.
We will poll events in the directory and once some event is triggered (based on the WatchKey definition)
we will print the type of event occurred and the name of the file/directory on which the event occurred. Once done, we will reset the watch key.</p>
<pre><code class="java">while (true) {
watchKey=watcherSvc.take();
for (WatchEvent&lt;?&gt; event: watchKey.pollEvents()) {
WatchEvent&lt;Path&gt; watchEvent = castEvent(event);
System.out.println(event.kind().name().toString() + " "
+ _directotyToWatch.resolve(watchEvent.context()));
watchKey.reset();
}
}