I'm working on a CoAP app using Eclipse Californium that will declare explicitly only the root resource path, and the rest of the resources should be served and resolved through a wildcard /root/* just like on REST APIs or servlets.
Is there any way to achieve that ?
Ok I managed to do it.
So after a few hours of digging on their Source code here is what ended up doing.
Note that it works but it's only to show how it could be done, it's still a work on progress (I did this in 3h) as I removed some code like observer etc..
As soon as I have some time, I'll digg onto the Californium Api more and make this generic and optimized I'll create a Github project and link it here.
1 : Create a model class
public class ProxyRes {
public CoapResource coapRes;
public String path;
public ProxyRes () {
}
public CoapResource getCoapRes () {
return coapRes;
}
public void setCoapRes (CoapResource coapRes) {
this.coapRes = coapRes;
}
public String getPath () {
return path;
}
public void setPath (String path) {
this.path = path;
}
}
2 : Create an abstract CoapResource that should inject the Wildcards list
public abstract class AbstractResource extends CoapResource {
private LinkedList<String> wildcards;
protected AbstractResource (String name) {
super (name);
}
protected AbstractResource (String name, boolean visible) {
super (name, visible);
}
public LinkedList<String> getWildcards () {
return wildcards;
}
public void setWildcards (LinkedList<String> wildcards) {
this.wildcards = wildcards;
}
}
3 : Create a Temperature Resource extending AbstractResource
public class TemperatureResource extends AbstractResource {
public TemperatureResource () {
super (ResourceSpecs.House.Sensors.Temperature);
getAttributes ().setTitle ("Temperature resource !");
}
#Override
public void handleGET (CoapExchange exchange) {
String response = "The temperature";
if (getWildcard () != null) {
response += " of the " + getWildcard ().get (0) + " on the " + getWildcard ().get (1);
}
response += " is : 25 degree C";
exchange.respond (response);
}
}
4 : Create a resources directory on the root of my eclipse project, with json conf files of my resources
{
"verb": "get",
"endpoint": "/houses/*/rooms/*/sensors/temperature",
"class": "com.wild.coap.resources.TemperatureResource"
}
5 : Create a Resources Loader (class that will load the specs definition of the resources and instantiate them independently instead of creating a Tree on the server)
public class ResourcesLoader {
private final static String Path = new File (".").getAbsolutePath () + File.separator + "resources";
private List<ProxyRes> resourcesList;
public ResourcesLoader () throws Exception {
resourcesList = new ArrayList<ProxyRes> ();
File resources = new File (Path);
for (String resName : resources.list ()) {
File resFile = new File (resources, resName);
InputStream is = new FileInputStream (resFile);
JsonObject o = new JsonObject (is);
resourcesArr.add (o);
resourcesList.add (buildObject (o));
}
}
private ProxyRes buildObject (JsonObject o) throws ClassNotFoundException, InstantiationException, IllegalAccessException {
ProxyRes r = new ProxyRes ();
r.setPath (o.getString ("endpoint"));
Class<?> clazz = Class.forName (o.getString ("class"));
CoapResource coapRes = (CoapResource)clazz.newInstance ();
r.setCoapRes (coapRes);
return r;
}
public List<ProxyRes> getResourcesList () {
return resourcesList;
}
}
6 : Create a Custom MessageDelieverer
public class DynamicMessageDeliverer implements MessageDeliverer {
private final List<ProxyRes> resources;
public DynamicMessageDeliverer (List<ProxyRes> resources) {
this.resources = resources;
}
public void deliverRequest (final Exchange exchange) {
Request request = exchange.getRequest ();
List<String> path = request.getOptions ().getUriPath ();
final Resource resource = registerResources (path);
if (resource != null) {
executeResource (exchange, resource);
} else {
exchange.sendResponse (new Response (ResponseCode.NOT_FOUND));
throw new RuntimeException ("Did not find resource " + path.toString() + " requested by " + request.getSource()+":"+request.getSourcePort());
}
}
private void executeResource (final Exchange exchange, final Resource resource) {
// Get the executor and let it process the request
Executor executor = resource.getExecutor ();
if (executor != null) {
exchange.setCustomExecutor ();
executor.execute (new Runnable () {
public void run () {
resource.handleRequest (exchange);
}
});
} else {
resource.handleRequest (exchange);
}
}
private Resource registerResources (List<String> list) {
LinkedList<String> path = new LinkedList<String> (list);
String flatRequestedEndpoint = Arrays.toString (path.toArray ());
LinkedList<String> wildcards = new LinkedList <String> ();
ProxyRes retainedResource = null;
for (ProxyRes proxyRes : resources) {
String[] res = proxyRes.getPath ().replaceFirst ("/", "").split ("/");
int length = res.length;
if (length != path.size ()) {
continue;
}
String flatResEndpoint = Arrays.toString (res);
if (flatResEndpoint.equals (flatRequestedEndpoint)) {
retainedResource = proxyRes;
break;
}
boolean match = true;
for (int i = 0; i < length; i ++) {
String str = res[i];
if (str.equals ("*")) {
wildcards.add (path.get (i));
continue;
}
if (!str.equals (path.get (i))) {
match = false;
break;
}
}
if (!match) {
wildcards.clear ();
continue;
}
retainedResource = proxyRes;
break;
}
if (retainedResource == null) {
return null;
}
((AbstractResource)retainedResource.getCoapRes ()).setWildcard (wildcards);
return retainedResource.getCoapRes ();
}
public void deliverResponse (Exchange exchange, Response response) {
if (response == null) throw new NullPointerException();
if (exchange == null) throw new NullPointerException();
if (exchange.getRequest() == null) throw new NullPointerException();
exchange.getRequest().setResponse(response);
Request request = exchange.getRequest ();
List<String> path = request.getOptions ().getUriPath ();
System.out.println ("Path retrieved : " + Arrays.toString (path.toArray ()));
}
}
7 : Create the Server
public class WildCoapServer extends CoapServer {
private static final int COAP_PORT = NetworkConfig.getStandard ().getInt (NetworkConfig.Keys.COAP_PORT);
public WildCoapServer () throws Exception {
// add endpoints on all IP addresses
addEndpoints ();
ResourcesLoader resLoader = new ResourcesLoader ();
List<ProxyRes> resources = resLoader.getResourcesList ();
setMessageDeliverer (new DynamicMessageDeliverer (resources));
}
#Override
protected Resource createRoot () {
return new WildRootResource ();
}
// Add individual endpoints listening on default CoAP port on all IPv4 addresses of all network interfaces.
private void addEndpoints () {
for (InetAddress addr : EndpointManager.getEndpointManager ().getNetworkInterfaces ()) {
// only binds to IPv4 addresses and localhost
if (addr instanceof Inet4Address || addr.isLoopbackAddress ()) {
InetSocketAddress bindToAddress = new InetSocketAddress (addr, COAP_PORT);
addEndpoint (new CoapEndpoint (bindToAddress));
}
}
}
}
8 : Start the server
public class Main {
public static void main (String[] args) {
try {
WildCoapServer server = new WildCoapServer ();
server.start ();
} catch (Exception e) {
throw new RuntimeException (e.getMessage (), e);
}
}
}
9 : Consume the Temperature resource from a client
public class Client {
public static void main (String[] args) {
URI uri = null;
try {
uri = new URI ("coap://192.168.200.1:5683/houses/house1/rooms/kitchen/sensors/temperature");
} catch (URISyntaxException e) {
throw new RuntimeException (e.getMessage (), e);
}
CoapClient client = new CoapClient (uri);
CoapResponse response = client.get ();
if (response != null) {
System.out.println (response.getCode ());
System.out.println (response.getOptions ());
System.out.println (response.getResponseText ());
System.out.println ("\nADVANCED\n");
// access advanced API with access to more details through .advanced ()
System.out.println (Utils.prettyPrint (response));
} else {
System.out.println ("No response received.");
}
}
}
Hope that helps someone.
This is my solution for this problem.
CoapResource wildcard = new CoapResource("*") {
#Override
public void handleGET(CoapExchange exchange) {
...
}
};
CoapResource root = new CoapResource("root") {
#Override
public Resource getChild(String name) {
return wildcard;
}
};
Related
import jade.core.Agent;
import jade.core.Runtime;
import jade.core.Profile;
import jade.core.ProfileImpl;
import jade.core.behaviours.*;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
public class Main {
public static void main(String[] args) {
Runtime rt = Runtime.instance();
Profile p = new ProfileImpl();
AgentContainer container = rt.createMainContainer(p);
try {
AgentController seller = jade.core.container.createNewAgent("Seller", SellerAgent.class, null);
seller.start();
String[] buyerArgs = new String[]{"A"};
AgentController buyer1 = container.createNewAgent("B1", BuyerAgent.class, buyerArgs);
buyer1.start();
buyerArgs[0] = "B";
AgentController buyer2 = container.createNewAgent("B2", BuyerAgent.class, buyerArgs);
buyer2.start();
buyerArgs[0] = "A";
AgentController buyer3 = container.createNewAgent("B3", BuyerAgent.class, buyerArgs);
buyer3.start();
buyerArgs[0] = "B";
AgentController buyer4 = container.createNewAgent("B4", BuyerAgent.class, buyerArgs);
buyer4.start();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public class BuyerAgent extends Agent {
private String requestedProduct;
private String sellerName;
private List<String> purchasedProducts = new ArrayList<>();
protected void setup() {
// Get the requested product name as an argument
Object[] args = getArguments();
if (args != null && args.length > 0) {
requestedProduct = (String) args[0];
}
// Add the behavior to request the product from the seller
addBehaviour(new RequestProductBehaviour());
}
private class RequestProductBehaviour extends OneShotBehaviour {
public void action() {
ACLMessage message = new ACLMessage(ACLMessage.REQUEST);
message.setContent(requestedProduct);
message.addReceiver(sellerName);
myAgent.send(message);
// Wait for the seller's response
addBehaviour(new PurchaseResponseBehaviour());
}
}
private class PurchaseResponseBehaviour extends SimpleBehaviour {
private boolean receivedResponse = false;
public void action() {
MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.INFORM);
ACLMessage message = myAgent.receive(mt);
if (message != null) {
// Product was available and was sold to this buyer
purchasedProducts.add(requestedProduct);
receivedResponse = true;
} else {
block();
}
}
public boolean done() {
if (receivedResponse) {
System.out.println(getLocalName() + " purchased: " + purchasedProducts);
}
return receivedResponse;
}
}
}
public class SellerAgent extends Agent {
private int itemsA = 2;
private int itemsB = 2;
private List<String> buyers = new ArrayList<>();
protected void setup() {
// Add the behavior to handle product request messages
addBehaviour(new HandleRequestBehaviour());
}
private class HandleRequestBehaviour extends CyclicBehaviour {
public void action() {
MessageTemplate mt = MessageTemplate.MatchPerformative(ACLMessage.REQUEST);
ACLMessage message = myAgent.receive(mt);
if (message != null) {
String product = message.getContent();
String buyerName = message.getSender().getLocalName();
ACLMessage reply = message.createReply();
if (buyerName.equals("B3") && product.equals("B")) {
// Seller cannot sell product B to buyer B3
reply.setPerformative(ACLMessage.FAILURE);
reply.setContent("Not allowed");
} else if (product.equals("A") && itemsA > 0) {
itemsA--;
reply.setPerformative(ACLMessage.INFORM);
buyers.add(buyerName);
} else if (product.equals("B") && itemsB >
0) {
itemsB--;
reply.setPerformative(ACLMessage.INFORM);
buyers.add(buyerName);
} else {
reply.setPerformative(ACLMessage.FAILURE);
reply.setContent("Not available");
}
myAgent.send(reply);
} else {
block();
}
}
}
protected void takeDown() {
System.out.println("Seller " + getLocalName() + " sold to: " + buyers);
}
}
This code gives me errors below:
Exception in thread "main" java.lang.Error: Unresolved compilation problems:
The method instance() is undefined for the type Runtime
Profile cannot be resolved to a type
ProfileImpl cannot be resolved to a type
AgentContainer cannot be resolved to a type
AgentController cannot be resolved to a type
jade cannot be resolved
AgentController cannot be resolved to a type
AgentController cannot be resolved to a type
AgentController cannot be resolved to a type
AgentController cannot be resolved to a type
at Main.main(main.java:10)
I have written a controller which is a default for MototuploadService(for Motor Upload), but I need to make one Factory Design so that
based on parentPkId, need to call HealUploadService, TempUploadService, PersonalUploadService etc which will have separate file processing stages.
controller is below.
#RequestMapping(value = "/csvUpload", method = RequestMethod.POST)
public List<String> csvUpload(#RequestParam String parentPkId, #RequestParam List<MultipartFile> files)
throws IOException, InterruptedException, ExecutionException, TimeoutException {
log.info("Entered method csvUpload() of DaoController.class");
List<String> response = new ArrayList<String>();
ExecutorService executor = Executors.newFixedThreadPool(10);
CompletionService<String> compService = new ExecutorCompletionService<String>(executor);
List< Future<String> > futureList = new ArrayList<Future<String>>();
for (MultipartFile f : files) {
compService.submit(new ProcessMutlipartFile(f ,parentPkId,uploadService));
futureList.add(compService.take());
}
for (Future<String> f : futureList) {
long timeout = 0;
System.out.println(f.get(timeout, TimeUnit.SECONDS));
response.add(f.get());
}
executor.shutdown();
return response;
}
Here is ProcessMutlipartFile class which extends the callable interface, with CompletionService's compService.submit() invoke this class, which in turn executes call() method, which will process a file.
public class ProcessMutlipartFile implements Callable<String>
{
private MultipartFile file;
private String temp;
private MotorUploadService motUploadService;
public ProcessMutlipartFile(MultipartFile file,String temp, MotorUploadService motUploadService )
{
this.file=file;
this.temp=temp;
this.motUploadService=motUploadService;
}
public String call() throws Exception
{
return motUploadService.csvUpload(temp, file);
}
}
Below is MotorUploadService class, where I'm processing uploaded CSV file, line by line and then calling validateCsvData() method to validate Data,
which returns ErrorObject having line number and Errors associated with it.
if csvErrorRecords is null, then error-free and proceed with saving to Db.
else save errorList to Db and return Upload Failure.
#Component
public class MotorUploadService {
#Value("${external.resource.folder}")
String resourceFolder;
public String csvUpload(String parentPkId, MultipartFile file) {
String OUT_PATH = resourceFolder;
try {
DateFormat df = new SimpleDateFormat("yyyyMMddhhmmss");
String filename = file.getOriginalFilename().split(".")[0] + df.format(new Date()) + file.getOriginalFilename().split(".")[1];
Path path = Paths.get(OUT_PATH,fileName)
Files.copy(file.getInputStream(), path, StandardCopyOption.REPLACE_EXISTING);
}
catch(IOException e){
e.printStackTrace();
return "Failed to Upload File...try Again";
}
List<TxnMpMotSlaveRaw> txnMpMotSlvRawlist = new ArrayList<TxnMpMotSlaveRaw>();
try {
BufferedReader br = new BufferedReader(new InputStreamReader(file.getInputStream()));
String line = "";
int header = 0;
int lineNum = 1;
TxnMpSlaveErrorNew txnMpSlaveErrorNew = new TxnMpSlaveErrorNew();
List<CSVErrorRecords> errList = new ArrayList<CSVErrorRecords>();
while ((line = br.readLine()) != null) {
// TO SKIP HEADER
if (header == 0) {
header++;
continue;
}
lineNum++;
header++;
// Use Comma As Separator
String[] csvDataSet = line.split(",");
CSVErrorRecords csvErrorRecords = validateCsvData(lineNum, csvDataSet);
System.out.println("Errors from csvErrorRecords is " + csvErrorRecords);
if (csvErrorRecords.equals(null) || csvErrorRecords.getRecordNo() == 0) {
//Function to Save to Db
} else {
// add to errList
continue;
}
}
if (txnMpSlaveErrorNew.getErrRecord().size() == 0) {
//save all
return "Successfully Uploaded " + file.getOriginalFilename();
}
else {
// save the error in db;
return "Failure as it contains Faulty Information" + file.getOriginalFilename();
}
} catch (IOException ex) {
ex.printStackTrace();
return "Failure Uploaded " + file.getOriginalFilename();
}
}
private TxnMpMotSlaveRaw saveCsvData(String[] csvDataSet, String parentPkId) {
/*
Mapping csvDataSet to PoJo
returning Mapped Pojo;
*/
}
private CSVErrorRecords validateCsvData(int lineNum, String[] csvDataSet) {
/*
Logic for Validation goes here
*/
}
}
How to make it as a factory design pattern from controller,
so that if
parentPkId='Motor' call MotorUploadService,
parentPkId='Heal' call HealUploadService
I'm not so aware of the Factory Design pattern, please help me out.
Thanks in advance.
If I understood the question, in essence you would create an interface, and then return a specific implementation based upon the desired type.
So
public interface UploadService {
void csvUpload(String temp, MultipartFile file) throws IOException;
}
The particular implementations
public class MotorUploadService implements UploadService
{
public void csvUpload(String temp, MultipartFile file) {
...
}
}
public class HealUploadService implements UploadService
{
public void csvUpload(String temp, MultipartFile file) {
...
}
}
Then a factory
public class UploadServiceFactory {
public UploadService getService(String type) {
if ("Motor".equals(type)) {
return new MotorUploadService();
}
else if ("Heal".equals(type)) {
return new HealUploadService();
}
}
}
The factory might cache the particular implementations. One can also use an abstract class rather than an interface if appropriate.
I think you currently have a class UploadService but that is really the MotorUploadService if I followed your code, so I would rename it to be specific.
Then in the controller, presumably having used injection for the UploadServiceFactory
...
for (MultipartFile f : files) {
UploadService uploadSrvc = uploadServiceFactory.getService(parentPkId);
compService.submit(new ProcessMutlipartFile(f ,parentPkId,uploadService));
futureList.add(compService.take());
}
So with some additional reading in your classes:
public class ProcessMutlipartFile implements Callable<String>
{
private MultipartFile file;
private String temp;
private UploadService uploadService;
// change to take the interface UploadService
public ProcessMutlipartFile(MultipartFile file,String temp, UploadService uploadService )
{
this.file=file;
this.temp=temp;
this.uploadService=uploadService;
}
public String call() throws Exception
{
return uploadService.csvUpload(temp, file);
}
}
I was given exercise that I need to refactor several java projects.
Only those 2 left which I truly don't have an idea how to refactor.
csv.writer
public class CsvWriter {
public CsvWriter() {
}
public void write(String[][] lines) {
for (int i = 0; i < lines.length; i++)
writeLine(lines[i]);
}
private void writeLine(String[] fields) {
if (fields.length == 0)
System.out.println();
else {
writeField(fields[0]);
for (int i = 1; i < fields.length; i++) {
System.out.print(",");
writeField(fields[i]);
}
System.out.println();
}
}
private void writeField(String field) {
if (field.indexOf(',') != -1 || field.indexOf('\"') != -1)
writeQuoted(field);
else
System.out.print(field);
}
private void writeQuoted(String field) {
System.out.print('\"');
for (int i = 0; i < field.length(); i++) {
char c = field.charAt(i);
if (c == '\"')
System.out.print("\"\"");
else
System.out.print(c);
}
System.out.print('\"');
}
}
csv.writertest
public class CsvWriterTest {
#Test
public void testWriter() {
CsvWriter writer = new CsvWriter();
String[][] lines = new String[][] {
new String[] {},
new String[] { "only one field" },
new String[] { "two", "fields" },
new String[] { "", "contents", "several words included" },
new String[] { ",", "embedded , commas, included",
"trailing comma," },
new String[] { "\"", "embedded \" quotes",
"multiple \"\"\" quotes\"\"" },
new String[] { "mixed commas, and \"quotes\"", "simple field" } };
// Expected:
// -- (empty line)
// only one field
// two,fields
// ,contents,several words included
// ",","embedded , commas, included","trailing comma,"
// """","embedded "" quotes","multiple """""" quotes"""""
// "mixed commas, and ""quotes""",simple field
writer.write(lines);
}
}
test
public class Configuration {
public int interval;
public int duration;
public int departure;
public void load(Properties props) throws ConfigurationException {
String valueString;
int value;
valueString = props.getProperty("interval");
if (valueString == null) {
throw new ConfigurationException("monitor interval");
}
value = Integer.parseInt(valueString);
if (value <= 0) {
throw new ConfigurationException("monitor interval > 0");
}
interval = value;
valueString = props.getProperty("duration");
if (valueString == null) {
throw new ConfigurationException("duration");
}
value = Integer.parseInt(valueString);
if (value <= 0) {
throw new ConfigurationException("duration > 0");
}
if ((value % interval) != 0) {
throw new ConfigurationException("duration % interval");
}
duration = value;
valueString = props.getProperty("departure");
if (valueString == null) {
throw new ConfigurationException("departure offset");
}
value = Integer.parseInt(valueString);
if (value <= 0) {
throw new ConfigurationException("departure > 0");
}
if ((value % interval) != 0) {
throw new ConfigurationException("departure % interval");
}
departure = value;
}
}
public class ConfigurationException extends Exception {
private static final long serialVersionUID = 1L;
public ConfigurationException() {
super();
}
public ConfigurationException(String arg0) {
super(arg0);
}
public ConfigurationException(String arg0, Throwable arg1) {
super(arg0, arg1);
}
public ConfigurationException(Throwable arg0) {
super(arg0);
}
}
configuration.test
public class ConfigurationTest{
#Test
public void testGoodInput() throws IOException {
String data = "interval = 10\nduration = 100\ndeparture = 200\n";
Properties input = loadInput(data);
Configuration props = new Configuration();
try {
props.load(input);
} catch (ConfigurationException e) {
assertTrue(false);
return;
}
assertEquals(props.interval, 10);
assertEquals(props.duration, 100);
assertEquals(props.departure, 200);
}
#Test
public void testNegativeValues() throws IOException {
processBadInput("interval = -10\nduration = 100\ndeparture = 200\n");
processBadInput("interval = 10\nduration = -100\ndeparture = 200\n");
processBadInput("interval = 10\nduration = 100\ndeparture = -200\n");
}
#Test
public void testInvalidDuration() throws IOException {
processBadInput("interval = 10\nduration = 99\ndeparture = 200\n");
}
#Test
public void testInvalidDeparture() throws IOException {
processBadInput("interval = 10\nduration = 100\ndeparture = 199\n");
}
#Test
private void processBadInput(String data) throws IOException {
Properties input = loadInput(data);
boolean failed = false;
Configuration props = new Configuration();
try {
props.load(input);
} catch (ConfigurationException e) {
failed = true;
}
assertTrue(failed);
}
#Test
private Properties loadInput(String data) throws IOException {
InputStream is = new StringBufferInputStream(data);
Properties input = new Properties();
input.load(is);
is.close();
return input;
}
}
Ok, here some advice regarding the code.
CsvWriter
The bad thing is that you print everything to System.out. It will be hard to test without mocks. Instead I suggest you to add field PrintStream which defines where all data will go.
import java.io.PrintStream;
public class CsvWriter {
private final PrintStream printStream;
public CsvWriter() {
this.printStream = System.out;
}
public CsvWriter(PrintStream printStream) {
this.printStream = printStream;
}
...
You then write everything to this stream. This refactoring easy since you use replace function(Ctrl+R in IDEA). Here is the example how you do it.
private void writeField(String field) {
if (field.indexOf(',') != -1 || field.indexOf('\"') != -1)
writeQuoted(field);
else
printStream.print(field);
}
Others stuff seems ok in this class.
CsvWriterTest
First thing first you don't check all logic in a single method. Make small methods with different kind of tests. It's ok to keep your current test though. Sometimes it's useful to check most of the logic in a complex scenario.
Also pay attention to the names of the methods. Check this
Obviously you test doesn't check the results. That's why we need this functionality with PrintStream. We can build a PrintStream on top of the instance of ByteArrayOutputStream. We then construct a string and check if the content is valid. Here is how you can easily check what was written
public class CsvWriterTest {
private ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
private PrintStream printStream = new PrintStream(byteArrayOutputStream);
#Test
public void testWriter() {
CsvWriter writer = new CsvWriter(printStream);
... old logic here ...
writer.write(lines);
String result = new String(byteArrayOutputStream.toByteArray());
Assert.assertTrue(result.contains("two,fields"));
Configuration
Make fields private
Make messages more concise
ConfigurationException
Seems good about serialVersionUID. This thing is needed for serialization/deserialization.
ConfigurationTest
Do not use assertTrue(false/failed); Use Assert.fail(String) with some message which is understandable.
Tip: if you don't have much experience and need to refactor code like this, you may want to read some chapters of Effective Java 2nd edition by Joshua Bloch. The book is not so big so you can read it in a week and it has some rules how to write clean and understandable code.
I am developing a voice-based app in android and facing some problems please see below code,
Java File 1
file = .wav file
public static AudioInputStream getAudioInputStream(File file) throws UnsupportedAudioFileException, IOException {
return getAudioInputStreamImpl(file);
}
private static AudioInputStream getAudioInputStreamImpl(Object source) throws UnsupportedAudioFileException, IOException {
GetAudioInputStreamAudioFileReaderAction action = new GetAudioInputStreamAudioFileReaderAction(source);
doAudioFileReaderIteration(action);
AudioInputStream audioInputStream = action.getAudioInputStream();
if (audioInputStream != null) {
return audioInputStream;
}
throw new UnsupportedAudioFileException("format not supported");
}
private static void doAudioFileReaderIteration(AudioFileReaderAction action) throws IOException {
Iterator audioFileReaders = TAudioConfig.getAudioFileReaders();
boolean bCompleted = false;
while (audioFileReaders.hasNext() && !bCompleted) {
AudioFileReader audioFileReader = (AudioFileReader) audioFileReaders.next();
bCompleted = action.handleAudioFileReader(audioFileReader);
}
}
Java file 2 (TAudioConfig)
public static synchronized Iterator<AudioFileReader> getAudioFileReaders() {
Iterator<AudioFileReader> it;
synchronized (TAudioConfig.class) {
it = getAudioFileReadersImpl().iterator();
}
return it;
}
private static synchronized Set<AudioFileReader> getAudioFileReadersImpl() {
Set<AudioFileReader> set;
synchronized (TAudioConfig.class) {
if (sm_audioFileReaders == null) {
sm_audioFileReaders = new ArraySet();
registerAudioFileReaders();
}
set = sm_audioFileReaders;
}
return set;
}
private static void registerAudioFileReaders() {
TInit.registerClasses(AudioFileReader.class, new C00001());
}
Java File 3 (TInit)
public static void registerClasses(Class providerClass, ProviderRegistrationAction action) {
Iterator providers = Service.providers(providerClass);
if (providers != null) {
while (providers.hasNext()) {
try {
action.register(providers.next());
} catch (Throwable e) {
}
}
}
}
Java File 4 (Service)
public static Iterator<?> providers(Class<?> cls) {
String strFullName = "com/example/voiceautomator/AudioFileReader.class";
Iterator<?> iterator = createInstancesList(strFullName).iterator();
return iterator;
}
private static List<Object> createInstancesList(String strFullName) {
List<Object> providers = new ArrayList<Object>();
Iterator<?> classNames = createClassNames(strFullName);
if (classNames != null) {
while (classNames.hasNext()) {
String strClassName = (String) classNames.next();
try {
Class<?> cls = Class.forName(strClassName, REVERSE_ORDER, ClassLoader.getSystemClassLoader());
providers.add(0, cls.newInstance());
} catch (Throwable e) {
}
}
}
return providers;
}
private static Iterator<String> createClassNames(String strFullName) {
Set<String> providers = new ArraySet<String>();
Enumeration<?> configs = null;
try {
configs = Service.class.getClassLoader().getSystemResources(strFullName);
} catch (Throwable e) {
}
if (configs != null) {
while (configs.hasMoreElements()) {
URL configFileUrl = (URL) configs.nextElement();
InputStream input = null;
try {
input = configFileUrl.openStream();
} catch (Throwable e2) {
}
if (input != null) {
BufferedReader reader = new BufferedReader(new InputStreamReader(input));
try {
for (String strLine = reader.readLine(); strLine != null; strLine = reader.readLine()) {
strLine = strLine.trim();
int nPos = strLine.indexOf(35);
if (nPos >= 0) {
strLine = strLine.substring(0, nPos);
}
if (strLine.length() > 0) {
providers.add(strLine);
}
}
} catch (Throwable e22) {
}
}
}
}
Iterator<String> iterator = providers.iterator();
return iterator;
}
getClassLoader().getSystemResources in the Java File 4 (Service) gives me TwoEnumerationsInOne and configs.hasMoreElements() gives false so not able to go into while loop.
AudioFileReader.java is included in the package
Please guide me to resolve this issue?
Please don't forget I am working on this code in an android project
Please see the value of configs here
http://capsicumtech.in/Screenshot_1.png
Thanks in advance.
I am a beginner when it comes to IntelliJ plugin development but i want my plugin to register a new Module Type in the "New Project" / "New Module" windows.
I already searched through the Documentation for plugin developers but wasn't able to find anything useful. I also looked at existing plugins like Kotlin and Scala which also add new Module types but I can't figure out how to get a finished ModuleType to show up in the dialogs mentioned above.
What do I have to change in the plugin.xml file? I already added extensions and created java classes for ModuleType, ModuleBuilder and the ModuleConfigurationExtensionProvider but that doesn't change anything.
I hope you can help me and thanks in advance.
This can be achieved through New Project Wizard feature of IntelliJ IDEA, by providing your Module / Project type implementation class of ModuleBuilder i.e by extending the intelliJ IDEA provided extension point for the same (com.intellij).
You need the below changes to make in your plugin.xml for making appear your new Module / Project type in New Project Wizard project /modules types list.
<extensions defaultExtensionNs="com.intellij">
<moduleBuilder builderClass="com.yourcompany.wizards.YourModuleBuilder"/>
</extensions>
Provide your ModuleBuilder class with package to buildlerClass attribute, thats enough.
Here is sample ModuleBuilder implementation:
public class AsposeJavaModuleBuilder extends ModuleBuilder implements SourcePathsBuilder {
private Project myProject;
ResourceBundle bundle = ResourceBundle.getBundle("Bundle");
#Override
public String getBuilderId() {
return getClass().getName();
}
#Override
public String getPresentableName() {
return "Aspose Application";
}
#Override
public String getDescription() {
return bundle.getString("AsposeWizardPanel.myMainPanel.description");
}
#Override
public Icon getBigIcon() {
return AsposeIcons.AsposeMedium;
}
#Override
public Icon getNodeIcon() {
return AsposeIcons.AsposeLogo;
}
#Override
public ModuleWizardStep[] createWizardSteps(#NotNull WizardContext wizardContext, #NotNull ModulesProvider modulesProvider) {
return new ModuleWizardStep[]{
new AsposeAPIsWizardStep(this, wizardContext),
};
}
#Override
public void setupRootModel(ModifiableRootModel rootModel) throws com.intellij.openapi.options.ConfigurationException {
setMyProject(rootModel.getProject());
final CompilerModuleExtension compilerModuleExtension = rootModel.getModuleExtension(CompilerModuleExtension.class);
compilerModuleExtension.setExcludeOutput(true);
if (myJdk != null) {
rootModel.setSdk(myJdk);
} else {
rootModel.inheritSdk();
}
ContentEntry contentEntry = doAddContentEntry(rootModel);
if (contentEntry != null) {
final List<Pair<String, String>> sourcePaths = getSourcePaths();
if (sourcePaths != null) {
for (final Pair<String, String> sourcePath : sourcePaths) {
String first = sourcePath.first;
new File(first).mkdirs();
final VirtualFile sourceRoot = LocalFileSystem.getInstance()
.refreshAndFindFileByPath(FileUtil.toSystemIndependentName(first));
if (sourceRoot != null) {
contentEntry.addSourceFolder(sourceRoot, false, sourcePath.second);
}
}
}
}
if (myCompilerOutputPath != null) {
// should set only absolute paths
String canonicalPath;
try {
canonicalPath = FileUtil.resolveShortWindowsName(myCompilerOutputPath);
} catch (IOException e) {
canonicalPath = myCompilerOutputPath;
}
compilerModuleExtension
.setCompilerOutputPath(VfsUtil.pathToUrl(FileUtil.toSystemIndependentName(canonicalPath)));
} else {
compilerModuleExtension.inheritCompilerOutputPath(true);
}
LibraryTable libraryTable = rootModel.getModuleLibraryTable();
for (Pair<String, String> libInfo : myModuleLibraries) {
final String moduleLibraryPath = libInfo.first;
final String sourceLibraryPath = libInfo.second;
Library library = libraryTable.createLibrary();
Library.ModifiableModel modifiableModel = library.getModifiableModel();
modifiableModel.addRoot(getUrlByPath(moduleLibraryPath), OrderRootType.CLASSES);
if (sourceLibraryPath != null) {
modifiableModel.addRoot(getUrlByPath(sourceLibraryPath), OrderRootType.SOURCES);
}
modifiableModel.commit();
}
RunnableHelper.runWhenInitialized(getMyProject(), new Runnable() {
public void run() {
System.out.println("Hello I came here");
final LibraryTablesRegistrar libTablesRegistrar = LibraryTablesRegistrar.getInstance();
final LibraryTable libraryTable = libTablesRegistrar.getLibraryTable(getMyProject());
final LibraryTable.ModifiableModel libTableModel = libraryTable.getModifiableModel();
Library library = libTableModel.createLibrary(AsposeConstants.LIBRARY_NAME);
libTableModel.commit();
#NonNls final String path = getContentEntryPath() + File.separator + AsposeConstants.LIB_FOLDER;
new File(path).mkdirs();
for (AsposeJavaAPI api : AsposeProject.getApiList().values()) {
System.out.println("Hello I came here2");
if (api.is_selected()) {
try {
System.out.println("Hello I came here3");
AsposeAPIsManager.copyDirectory(AsposeAPIsManager.getLibaryDownloadPath() + api.get_name().toLowerCase(), path + File.separator + api.get_name());
} catch (IOException ex) {
ex.printStackTrace();
}
String[] children = new File(path + File.separator + api.get_name().toLowerCase() + File.separator).list();
for (String _child : children) {
String jarPath = "jar://" + path + File.separator + api.get_name() + File.separator + _child + "!/";
Library.ModifiableModel model = library.getModifiableModel();
model.addRoot(jarPath, OrderRootType.CLASSES);
model.commit();
}
}
}
Collection<Module> modules = ModuleUtil.getModulesOfType(getMyProject(), StdModuleTypes.JAVA);
Iterator itr = modules.iterator();
Module module = null;
while (itr.hasNext()) {
module = (Module) itr.next();
break;
}
final ModuleRootManager moduleRootManager = ModuleRootManager.getInstance(module);
final ModifiableRootModel moduleRootModel = moduleRootManager.getModifiableModel();
final Library lib = libraryTable.getLibraryByName(AsposeConstants.LIBRARY_NAME);
if (moduleRootModel.findLibraryOrderEntry(lib) == null) {
moduleRootModel.addLibraryEntry(lib);
}
moduleRootModel.commit();
}
});
}
#Override
public String getGroupName() {
return JavaModuleType.JAVA_GROUP;
}
public Project getMyProject() {
return myProject;
}
public void setMyProject(Project myProject) {
this.myProject = myProject;
}
#Nullable
public ModuleWizardStep getCustomOptionsStep(WizardContext context, Disposable parentDisposable) {
AsposeIntroWizardStep step = new AsposeIntroWizardStep();
Disposer.register(parentDisposable, step);
return step;
}
private String myCompilerOutputPath;
// Pair<Source Path, Package Prefix>
private List<Pair<String, String>> mySourcePaths;
// Pair<Library path, Source path>
private final List<Pair<String, String>> myModuleLibraries = new ArrayList<Pair<String, String>>();
public final void setCompilerOutputPath(String compilerOutputPath) {
myCompilerOutputPath = acceptParameter(compilerOutputPath);
}
public List<Pair<String, String>> getSourcePaths() {
if (mySourcePaths == null) {
final List<Pair<String, String>> paths = new ArrayList<Pair<String, String>>();
#NonNls final String path = getContentEntryPath() + File.separator + "src";
new File(path).mkdirs();
paths.add(Pair.create(path, ""));
return paths;
}
return mySourcePaths;
}
public void setSourcePaths(List<Pair<String, String>> sourcePaths) {
mySourcePaths = sourcePaths != null ? new ArrayList<Pair<String, String>>(sourcePaths) : null;
}
public void addSourcePath(Pair<String, String> sourcePathInfo) {
if (mySourcePaths == null) {
mySourcePaths = new ArrayList<Pair<String, String>>();
}
mySourcePaths.add(sourcePathInfo);
}
public ModuleType getModuleType() {
return StdModuleTypes.JAVA;
}
#Override
public boolean isSuitableSdkType(SdkTypeId sdkType) {
return sdkType instanceof JavaSdkType;
}
#Nullable
#Override
public ModuleWizardStep modifySettingsStep(#NotNull SettingsStep settingsStep) {
return StdModuleTypes.JAVA.modifySettingsStep(settingsStep, this);
}
private static String getUrlByPath(final String path) {
return VfsUtil.getUrlForLibraryRoot(new File(path));
}
public void addModuleLibrary(String moduleLibraryPath, String sourcePath) {
myModuleLibraries.add(Pair.create(moduleLibraryPath, sourcePath));
}
#Nullable
protected static String getPathForOutputPathStep() {
return null;
}
}
For complete source code reference for creating new Module / Project Types in IntelliJ IDEA, please see the source code of Aspose Project Wizard (an IntelliJ IDEA Plugin By Aspose pty Ltd)
Source codes can be downloaded from the following URL:
https://asposejetbrains.codeplex.com/