Return-Path: X-Original-To: archive-asf-public-internal@cust-asf2.ponee.io Delivered-To: archive-asf-public-internal@cust-asf2.ponee.io Received: from cust-asf.ponee.io (cust-asf.ponee.io [163.172.22.183]) by cust-asf2.ponee.io (Postfix) with ESMTP id 53F23200B4C for ; Thu, 16 Jun 2016 10:12:08 +0200 (CEST) Received: by cust-asf.ponee.io (Postfix) id 50BE7160A63; Thu, 16 Jun 2016 08:12:08 +0000 (UTC) Delivered-To: archive-asf-public@cust-asf.ponee.io Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by cust-asf.ponee.io (Postfix) with SMTP id 312F2160A61 for ; Thu, 16 Jun 2016 10:12:06 +0200 (CEST) Received: (qmail 61440 invoked by uid 500); 16 Jun 2016 08:12:03 -0000 Mailing-List: contact commits-help@cloudstack.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@cloudstack.apache.org Delivered-To: mailing list commits@cloudstack.apache.org Received: (qmail 60699 invoked by uid 99); 16 Jun 2016 08:12:03 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 16 Jun 2016 08:12:03 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id DCC6CED312; Thu, 16 Jun 2016 08:12:02 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: sateesh@apache.org To: commits@cloudstack.apache.org Date: Thu, 16 Jun 2016 08:12:17 -0000 Message-Id: In-Reply-To: <3abf179c1ff24ceab07691879f2366aa@git.apache.org> References: <3abf179c1ff24ceab07691879f2366aa@git.apache.org> X-Mailer: ASF-Git Admin Mailer Subject: [16/50] [abbrv] git commit: updated refs/heads/deploy-from-snapshot to 44ba14d archived-at: Thu, 16 Jun 2016 08:12:08 -0000 http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/exception/ExceptionUtil.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/exception/ExceptionUtil.java b/utils/src/main/java/com/cloud/utils/exception/ExceptionUtil.java new file mode 100644 index 0000000..351d2ab --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/exception/ExceptionUtil.java @@ -0,0 +1,54 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.exception; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class ExceptionUtil { + public static String toString(Throwable th) { + return toString(th, true); + } + + public static String toString(Throwable th, boolean printStack) { + final StringWriter writer = new StringWriter(); + writer.append("Exception: " + th.getClass().getName() + "\n"); + writer.append("Message: "); + writer.append(th.getMessage()).append("\n"); + + if (printStack) { + writer.append("Stack: "); + th.printStackTrace(new PrintWriter(writer)); + } + return writer.toString(); + } + + @SuppressWarnings("unchecked") + public static void rethrow(Throwable t, Class clz) throws T { + if (clz.isAssignableFrom(t.getClass())) + throw (T)t; + } + + public static void rethrowRuntime(Throwable t) { + rethrow(t, RuntimeException.class); + rethrow(t, Error.class); + } + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/exception/ExecutionException.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/exception/ExecutionException.java b/utils/src/main/java/com/cloud/utils/exception/ExecutionException.java new file mode 100644 index 0000000..7b3bc61 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/exception/ExecutionException.java @@ -0,0 +1,49 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.exception; + +import com.cloud.utils.SerialVersionUID; + +/** + * a public method. + * + */ +public class ExecutionException extends Exception { + private static final long serialVersionUID = SerialVersionUID.ExecutionException; + + protected int csErrorCode; + + public ExecutionException(String msg, Throwable cause) { + super(msg, cause); + setCSErrorCode(CSExceptionErrorCode.getCSErrCode(this.getClass().getName())); + } + + public ExecutionException(String msg) { + super(msg); + } + + public void setCSErrorCode(int cserrcode) { + this.csErrorCode = cserrcode; + } + + public int getCSErrorCode() { + return this.csErrorCode; + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/exception/HypervisorVersionChangedException.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/exception/HypervisorVersionChangedException.java b/utils/src/main/java/com/cloud/utils/exception/HypervisorVersionChangedException.java new file mode 100644 index 0000000..55c273b --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/exception/HypervisorVersionChangedException.java @@ -0,0 +1,35 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.exception; + +import com.cloud.utils.SerialVersionUID; + +public class HypervisorVersionChangedException extends CloudRuntimeException { + + private static final long serialVersionUID = SerialVersionUID.CloudRuntimeException; + + public HypervisorVersionChangedException(String message) { + super(message); + } + + protected HypervisorVersionChangedException() { + super(); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/ChangeEvent.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/ChangeEvent.java b/utils/src/main/java/com/cloud/utils/fsm/ChangeEvent.java new file mode 100644 index 0000000..15f4f6e --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/ChangeEvent.java @@ -0,0 +1,24 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +public class ChangeEvent { + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/FiniteState.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/FiniteState.java b/utils/src/main/java/com/cloud/utils/fsm/FiniteState.java new file mode 100644 index 0000000..e6f2cd0 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/FiniteState.java @@ -0,0 +1,58 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +import java.util.List; +import java.util.Set; + +/** + * + * @param State + * @param Event + */ +public interface FiniteState { + /** + * @return the state machine being used. + */ + StateMachine getStateMachine(); + + /** + * get next state based on the event. + * @param event + * @return next State + */ + S getNextState(E event); + + /** + * Get the states that could have traveled to the current state + * via this event. + * @param event + * @return array of states + */ + List getFromStates(E event); + + /** + * Get the possible events that can happen from the current state. + * @return array of events. + */ + Set getPossibleEvents(); + + String getDescription(); +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/FiniteState2.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/FiniteState2.java b/utils/src/main/java/com/cloud/utils/fsm/FiniteState2.java new file mode 100644 index 0000000..14b9a5e --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/FiniteState2.java @@ -0,0 +1,34 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +import java.util.Set; + +public interface FiniteState2 { + + StateMachine2> getStateMachine(); + + T getNextState(ChangeEvent e) throws NoTransitionException; + + T getFromStates(ChangeEvent e); + + Set getPossibleEvents(); + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/FiniteStateObject.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/FiniteStateObject.java b/utils/src/main/java/com/cloud/utils/fsm/FiniteStateObject.java new file mode 100644 index 0000000..a57e3b4 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/FiniteStateObject.java @@ -0,0 +1,25 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +public interface FiniteStateObject { + + void setState(S state); +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/NoTransitionException.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/NoTransitionException.java b/utils/src/main/java/com/cloud/utils/fsm/NoTransitionException.java new file mode 100644 index 0000000..241e456 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/NoTransitionException.java @@ -0,0 +1,36 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +import com.cloud.utils.SerialVersionUID; + +/** + * Thrown by the state machine when there is no transition from one state + * to another. + * + */ +public class NoTransitionException extends Exception { + + private static final long serialVersionUID = SerialVersionUID.NoTransitionException; + + public NoTransitionException(String msg) { + super(msg); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/State.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/State.java b/utils/src/main/java/com/cloud/utils/fsm/State.java new file mode 100644 index 0000000..0af0e61 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/State.java @@ -0,0 +1,27 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +/** + * State represents one state for that object + */ +public interface State { + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/StateDao.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateDao.java b/utils/src/main/java/com/cloud/utils/fsm/StateDao.java new file mode 100644 index 0000000..43ce25c --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/StateDao.java @@ -0,0 +1,25 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +public interface StateDao { + boolean updateState(S currentState, E event, S nextState, V vo, Object data); + +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/StateListener.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateListener.java b/utils/src/main/java/com/cloud/utils/fsm/StateListener.java new file mode 100644 index 0000000..96e8be9 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/StateListener.java @@ -0,0 +1,43 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +public interface StateListener { + /** + * Event is triggered before state machine transition finished. + * If you want to get the state of vm before state machine changed, you need to listen on this event + * @param oldState VM's old state + * @param event that triggered this VM state change + * @param newState VM's new state + * @param vo the VM instance + * @param opaque host id + * @return + */ + public boolean preStateTransitionEvent(S oldState, E event, S newState, V vo, boolean status, Object opaque); + + /** + * Event is triggered after state machine transition finished + * @param transition The Transition fo the Event + * @param vo the VM instance + * @param status the state transition is allowed or not + * @return + */ + public boolean postStateTransitionEvent(StateMachine2.Transition transition, V vo, boolean status, Object opaque); +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/StateMachine.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateMachine.java b/utils/src/main/java/com/cloud/utils/fsm/StateMachine.java new file mode 100644 index 0000000..d6d5b4d --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/StateMachine.java @@ -0,0 +1,147 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +import java.util.ArrayList; +import java.util.Formatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Specifically, it implements the Moore machine. + * so someone else can add/modify states easily without regression. + * business logic anyways. + * + * @param state + * @param event + */ +public class StateMachine { + private final HashMap _states = new HashMap(); + private final StateEntry _initialStateEntry; + + public StateMachine() { + _initialStateEntry = new StateEntry(null); + } + + public void addTransition(S currentState, E event, S toState) { + StateEntry entry = null; + if (currentState == null) { + entry = _initialStateEntry; + } else { + entry = _states.get(currentState); + if (entry == null) { + entry = new StateEntry(currentState); + _states.put(currentState, entry); + } + } + + entry.addTransition(event, toState); + + entry = _states.get(toState); + if (entry == null) { + entry = new StateEntry(toState); + _states.put(toState, entry); + } + entry.addFromTransition(event, currentState); + } + + public Set getPossibleEvents(S s) { + StateEntry entry = _states.get(s); + return entry.nextStates.keySet(); + } + + public S getNextState(S s, E e) { + StateEntry entry = null; + if (s == null) { + entry = _initialStateEntry; + } else { + entry = _states.get(s); + assert entry != null : "Cannot retrieve transitions for state " + s.toString(); + } + + return entry.nextStates.get(e); + } + + public List getFromStates(S s, E e) { + StateEntry entry = _states.get(s); + if (entry == null) { + return new ArrayList(); + } + + return entry.prevStates.get(e); + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(1024); + _initialStateEntry.buildString(str); + for (StateEntry entry : _states.values()) { + entry.buildString(str); + } + return str.toString(); + } + + private class StateEntry { + public S state; + public HashMap nextStates; + public HashMap> prevStates; + + public StateEntry(S state) { + this.state = state; + nextStates = new HashMap(); + prevStates = new HashMap>(); + } + + public void addTransition(E e, S s) { + assert !nextStates.containsKey(e) : "State " + getStateStr() + " already contains a transition to state " + nextStates.get(e).toString() + " via event " + + e.toString() + ". Please revisit the rule you're adding to state " + s.toString(); + nextStates.put(e, s); + } + + public void addFromTransition(E e, S s) { + List l = prevStates.get(e); + if (l == null) { + l = new ArrayList(); + prevStates.put(e, l); + } + + assert !l.contains(s) : "Already contains the from transition " + e.toString() + " from state " + s.toString() + " to " + getStateStr(); + l.add(s); + } + + protected String getStateStr() { + return state == null ? "Initial" : state.toString(); + } + + public void buildString(StringBuilder str) { + str.append("State: ").append(getStateStr()).append("\n"); + for (Map.Entry nextState : nextStates.entrySet()) { + str.append(" --> Event: "); + Formatter format = new Formatter(); + str.append(format.format("%-30s", nextState.getKey().toString())); + str.append("----> State: "); + str.append(nextState.getValue().toString()); + str.append("\n"); + } + } + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java b/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java new file mode 100644 index 0000000..431d961 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/StateMachine2.java @@ -0,0 +1,261 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +import java.util.ArrayList; +import java.util.Formatter; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +/** + * Specifically, it implements the Moore machine. + * so someone else can add/modify states easily without regression. + * business logic anyways. + * + * @param state + * @param event + */ +public class StateMachine2> { + private final HashMap _states = new HashMap(); + private final StateEntry _initialStateEntry; + + private List> _listeners = new ArrayList>(); + + public StateMachine2() { + _initialStateEntry = new StateEntry(null); + + } + + public void addTransition(S currentState, E event, S toState) { + addTransition(new Transition(currentState, event, toState, null)); + } + + + public void addTransition(Transition transition) { + S currentState = transition.getCurrentState(); + E event = transition.getEvent(); + S toState = transition.getToState(); + StateEntry entry = null; + if (currentState == null) { + entry = _initialStateEntry; + } else { + entry = _states.get(currentState); + if (entry == null) { + entry = new StateEntry(currentState); + _states.put(currentState, entry); + } + } + + entry.addTransition(event, toState, transition); + + entry = _states.get(toState); + if (entry == null) { + entry = new StateEntry(toState); + _states.put(toState, entry); + } + entry.addFromTransition(event, currentState); + } + + public Set getPossibleEvents(S s) { + StateEntry entry = _states.get(s); + return entry.nextStates.keySet(); + } + + public S getNextState(S s, E e) throws NoTransitionException { + return getTransition(s, e).getToState(); + } + + public Transition getTransition(S s, E e) throws NoTransitionException { + StateEntry entry = null; + if (s == null) { + entry = _initialStateEntry; + } else { + entry = _states.get(s); + assert entry != null : "Cannot retrieve transitions for state " + s; + } + + Transition transition = entry.nextStates.get(e); + if (transition == null) { + throw new NoTransitionException("Unable to transition to a new state from " + s + " via " + e); + } + return transition; + } + + public List getFromStates(S s, E e) { + StateEntry entry = _states.get(s); + if (entry == null) { + return new ArrayList(); + } + + return entry.prevStates.get(e); + } + + public boolean transitTo(V vo, E e, Object opaque, StateDao dao) throws NoTransitionException { + S currentState = vo.getState(); + S nextState = getNextState(currentState, e); + Transition transition = getTransition(currentState, e); + + boolean transitionStatus = true; + if (nextState == null) { + transitionStatus = false; + } + + for (StateListener listener : _listeners) { + listener.preStateTransitionEvent(currentState, e, nextState, vo, transitionStatus, opaque); + } + + transitionStatus = dao.updateState(currentState, e, nextState, vo, opaque); + if (!transitionStatus) { + return false; + } + + for (StateListener listener : _listeners) { + listener.postStateTransitionEvent(transition, vo, transitionStatus, opaque); + } + + return true; + } + + public boolean registerListener(StateListener listener) { + synchronized (_listeners) { + return _listeners.add(listener); + } + } + + @Override + public String toString() { + StringBuilder str = new StringBuilder(1024); + _initialStateEntry.buildString(str); + for (StateEntry entry : _states.values()) { + entry.buildString(str); + } + return str.toString(); + } + + public static class Transition { + + private S currentState; + + private E event; + + private S toState; + + private List impacts; + + public static enum Impact { + USAGE + } + + public Transition(S currentState, E event, S toState, List impacts) { + this.currentState = currentState; + this.event = event; + this.toState = toState; + this.impacts = impacts; + } + + public S getCurrentState() { + return currentState; + } + + public E getEvent() { + return event; + } + + public S getToState() { + return toState; + } + + public boolean isImpacted(Impact impact) { + if (impacts == null || impacts.isEmpty()) { + return false; + } + return impacts.contains(impact); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + + Transition that = (Transition) o; + + if (currentState != null ? !currentState.equals(that.currentState) : that.currentState != null) return false; + if (event != null ? !event.equals(that.event) : that.event != null) return false; + if (toState != null ? !toState.equals(that.toState) : that.toState != null) return false; + + return true; + } + + @Override + public int hashCode() { + int result = currentState != null ? currentState.hashCode() : 0; + result = 31 * result + (event != null ? event.hashCode() : 0); + result = 31 * result + (toState != null ? toState.hashCode() : 0); + return result; + } + } + + private class StateEntry { + public S state; + public HashMap> nextStates; + public HashMap> prevStates; + + public StateEntry(S state) { + this.state = state; + prevStates = new HashMap>(); + nextStates = new HashMap>(); + } + + public void addTransition(E e, S s, Transition transition) { + assert !nextStates.containsKey(e) : "State " + getStateStr() + " already contains a transition to state " + nextStates.get(e).toString() + " via event " + + e.toString() + ". Please revisit the rule you're adding to state " + s.toString(); + nextStates.put(e, transition); + } + + public void addFromTransition(E e, S s) { + List l = prevStates.get(e); + if (l == null) { + l = new ArrayList(); + prevStates.put(e, l); + } + + assert !l.contains(s) : "Already contains the from transition " + e.toString() + " from state " + s.toString() + " to " + getStateStr(); + l.add(s); + } + + protected String getStateStr() { + return state == null ? "Initial" : state.toString(); + } + + public void buildString(StringBuilder str) { + str.append("State: ").append(getStateStr()).append("\n"); + for (Map.Entry> nextState : nextStates.entrySet()) { + str.append(" --> Event: "); + Formatter format = new Formatter(); + str.append(format.format("%-30s", nextState.getKey().toString())); + str.append("----> State: "); + str.append(nextState.getValue().toString()); + str.append("\n"); + } + } + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/fsm/StateObject.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/fsm/StateObject.java b/utils/src/main/java/com/cloud/utils/fsm/StateObject.java new file mode 100644 index 0000000..85dd441 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/fsm/StateObject.java @@ -0,0 +1,27 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.fsm; + +public interface StateObject { + /** + * @return finite state. + */ + S getState(); +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/mgmt/JmxUtil.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/mgmt/JmxUtil.java b/utils/src/main/java/com/cloud/utils/mgmt/JmxUtil.java new file mode 100644 index 0000000..49076f7 --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/mgmt/JmxUtil.java @@ -0,0 +1,90 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.mgmt; + +import java.lang.management.ManagementFactory; +import java.util.ArrayList; + +import javax.management.InstanceAlreadyExistsException; +import javax.management.InstanceNotFoundException; +import javax.management.MBeanRegistrationException; +import javax.management.MBeanServer; +import javax.management.MBeanServerFactory; +import javax.management.MalformedObjectNameException; +import javax.management.NotCompliantMBeanException; +import javax.management.ObjectName; + +public class JmxUtil { + public static ObjectName registerMBean(ManagementBean mbean) throws MalformedObjectNameException, InstanceAlreadyExistsException, MBeanRegistrationException, + NotCompliantMBeanException { + + return registerMBean(mbean.getName(), null, mbean); + } + + public static ObjectName registerMBean(String objTypeName, String objInstanceName, Object mbean) throws MalformedObjectNameException, InstanceAlreadyExistsException, + MBeanRegistrationException, NotCompliantMBeanException { + + String name = "com.cloud:type=" + objTypeName; + if (objInstanceName != null && !objInstanceName.isEmpty()) + name += ", name=" + objInstanceName; + ObjectName objectName = new ObjectName(name); + + ArrayList server = MBeanServerFactory.findMBeanServer(null); + if (server.size() > 0) { + MBeanServer mBeanServer = server.get(0); + if (!mBeanServer.isRegistered(objectName)) + mBeanServer.registerMBean(mbean, objectName); + return objectName; + } else { + MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + if (!mBeanServer.isRegistered(objectName)) + mBeanServer.registerMBean(mbean, objectName); + return objectName; + } + } + + public static void unregisterMBean(String objTypeName, String objInstanceName) throws MalformedObjectNameException, MBeanRegistrationException, + InstanceNotFoundException { + + ObjectName name = composeMBeanName(objTypeName, objInstanceName); + unregisterMBean(name); + } + + public static void unregisterMBean(ObjectName name) throws MalformedObjectNameException, MBeanRegistrationException, InstanceNotFoundException { + + ArrayList server = MBeanServerFactory.findMBeanServer(null); + if (server.size() > 0) { + MBeanServer mBeanServer = server.get(0); + mBeanServer.unregisterMBean(name); + } else { + MBeanServer mBeanServer = ManagementFactory.getPlatformMBeanServer(); + mBeanServer.unregisterMBean(name); + } + } + + private static ObjectName composeMBeanName(String objTypeName, String objInstanceName) throws MalformedObjectNameException { + + String name = "com.cloud:type=" + objTypeName; + if (objInstanceName != null && !objInstanceName.isEmpty()) + name += ", name=" + objInstanceName; + + return new ObjectName(name); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/mgmt/ManagementBean.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/mgmt/ManagementBean.java b/utils/src/main/java/com/cloud/utils/mgmt/ManagementBean.java new file mode 100644 index 0000000..387052e --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/mgmt/ManagementBean.java @@ -0,0 +1,27 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.mgmt; + +/** + * we ever need common use methods here. + */ +public interface ManagementBean { + String getName(); +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/mgmt/PropertyMapDynamicBean.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/mgmt/PropertyMapDynamicBean.java b/utils/src/main/java/com/cloud/utils/mgmt/PropertyMapDynamicBean.java new file mode 100644 index 0000000..d1689eb --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/mgmt/PropertyMapDynamicBean.java @@ -0,0 +1,120 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.mgmt; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.SortedSet; +import java.util.TreeSet; + +import javax.management.Attribute; +import javax.management.AttributeList; +import javax.management.AttributeNotFoundException; +import javax.management.DynamicMBean; +import javax.management.InvalidAttributeValueException; +import javax.management.MBeanAttributeInfo; +import javax.management.MBeanException; +import javax.management.MBeanInfo; +import javax.management.ReflectionException; + +public class PropertyMapDynamicBean implements DynamicMBean { + + private Map _propMap = new HashMap(); + + public PropertyMapDynamicBean() { + } + + public PropertyMapDynamicBean(Map propMap) { + _propMap = propMap; + } + + @Override + public synchronized Object getAttribute(String name) throws AttributeNotFoundException, MBeanException, ReflectionException { + if (_propMap != null) { + return _propMap.get(name); + } + + throw new AttributeNotFoundException("No such property " + name); + } + + @Override + public synchronized AttributeList getAttributes(String[] names) { + AttributeList list = new AttributeList(); + for (String name : names) { + Object value = _propMap.get(name); + if (value != null) + list.add(new Attribute(name, value)); + } + return list; + } + + @Override + public synchronized MBeanInfo getMBeanInfo() { + SortedSet names = new TreeSet(); + + for (String name : _propMap.keySet()) + names.add(name); + + MBeanAttributeInfo[] attrs = new MBeanAttributeInfo[names.size()]; + Iterator it = names.iterator(); + for (int i = 0; i < attrs.length; i++) { + String name = it.next(); + attrs[i] = new MBeanAttributeInfo(name, "java.lang.String", name, true, // isReadable + true, // isWritable + false); // isIs + } + + return new MBeanInfo(this.getClass().getName(), "Dynamic MBean", attrs, null, null, null); + } + + @Override + public synchronized Object invoke(String name, Object[] args, String[] sig) throws MBeanException, ReflectionException { + throw new ReflectionException(new NoSuchMethodException(name)); + } + + @Override + public synchronized void setAttribute(Attribute attr) throws AttributeNotFoundException, InvalidAttributeValueException, MBeanException, ReflectionException { + String name = attr.getName(); + if (name != null) + _propMap.put(name, attr.getValue()); + } + + @Override + public synchronized AttributeList setAttributes(AttributeList list) { + Attribute[] attrs = list.toArray(new Attribute[0]); + AttributeList retList = new AttributeList(); + for (Attribute attr : attrs) { + String name = attr.getName(); + Object value = attr.getValue(); + _propMap.put(name, value); + retList.add(new Attribute(name, value)); + } + return retList; + } + + public synchronized void addProp(String name, Object value) { + _propMap.put(name, value); + } + + public synchronized Object getProp(String name) { + return _propMap.get(name); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/net/Ip.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/net/Ip.java b/utils/src/main/java/com/cloud/utils/net/Ip.java new file mode 100644 index 0000000..09312bc --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/net/Ip.java @@ -0,0 +1,98 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.net; + +import java.io.Serializable; + +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.SerialVersionUID; + +/** + * Simple Ip implementation class that works with both ip4 and ip6. + * + */ +public class Ip implements Serializable, Comparable { + + private static final long serialVersionUID = SerialVersionUID.Ip; + + long ip; + + public Ip(long ip) { + this.ip = ip; + } + + public Ip(String ip) { + this.ip = NetUtils.ip2Long(ip); + } + + protected Ip() { + } + + public String addr() { + return toString(); + } + + public long longValue() { + return ip; + } + + @Override + public String toString() { + return NetUtils.long2Ip(ip); + } + + public boolean isIp4() { + return ip <= 2L * Integer.MAX_VALUE + 1; + } + + public boolean isIp6() { + return ip > Integer.MAX_VALUE; + } + + @Override + public int hashCode() { + return NumbersUtil.hash(ip); + } + + @Override + public boolean equals(Object obj) { + if (obj instanceof Ip) { + return ip == ((Ip)obj).ip; + } + return false; + } + + public boolean isSameAddressAs(Object obj) { + if (this.equals(obj)) { + return true; + } else if (obj instanceof String) { + return ip == NetUtils.ip2Long((String)obj); + } else if (obj instanceof Long) { + return ip == (Long)obj; + } else { + return false; + } + } + + @Override + public int compareTo(Ip that) { + return (int)(this.ip - that.ip); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/net/Ip4Address.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/net/Ip4Address.java b/utils/src/main/java/com/cloud/utils/net/Ip4Address.java new file mode 100644 index 0000000..0bd814d --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/net/Ip4Address.java @@ -0,0 +1,80 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.net; + +public class Ip4Address { + String _addr; + String _mac; + static final String s_empty_mac = "00:00:00:00:00:00"; + + public Ip4Address(String addr, String mac) { + _addr = addr; + _mac = mac; + } + + public Ip4Address(long addr, long mac) { + _addr = NetUtils.long2Ip(addr); + _mac = NetUtils.long2Mac(mac); + } + + public Ip4Address(String addr) { + this(addr, s_empty_mac); + } + + public Ip4Address(long addr) { + this(NetUtils.long2Ip(addr), s_empty_mac); + } + + public String ip4() { + return _addr; + } + + public String mac() { + return _mac; + } + + public long toLong() { + return NetUtils.ip2Long(_addr); + } + + @Override + public boolean equals(Object that) { + + if (that instanceof Ip4Address) { + Ip4Address ip4 = (Ip4Address)that; + return _addr.equals(ip4._addr) && (_mac == ip4._mac || _mac.equals(ip4._mac)); + } else { + return false; + } + } + + public boolean isSameAddressAs(Object other) { + if (other instanceof String) { // Assume that is an ip4 address in String form + return _addr.equals(other); + } else { + return equals(other); + } + } + + @Override + public int hashCode(){ + return _mac.hashCode()*_addr.hashCode(); + } +} http://git-wip-us.apache.org/repos/asf/cloudstack/blob/83fd8f60/utils/src/main/java/com/cloud/utils/net/MacAddress.java ---------------------------------------------------------------------- diff --git a/utils/src/main/java/com/cloud/utils/net/MacAddress.java b/utils/src/main/java/com/cloud/utils/net/MacAddress.java new file mode 100644 index 0000000..b9118cf --- /dev/null +++ b/utils/src/main/java/com/cloud/utils/net/MacAddress.java @@ -0,0 +1,367 @@ +// +// Licensed to the Apache Software Foundation (ASF) under one +// or more contributor license agreements. See the NOTICE file +// distributed with this work for additional information +// regarding copyright ownership. The ASF licenses this file +// to you under the Apache License, Version 2.0 (the +// "License"); you may not use this file except in compliance +// with the License. You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, +// software distributed under the License is distributed on an +// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +// KIND, either express or implied. See the License for the +// specific language governing permissions and limitations +// under the License. +// + +package com.cloud.utils.net; + +import static com.cloud.utils.AutoCloseableUtil.closeAutoCloseable; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.net.InetAddress; +import java.net.UnknownHostException; +import java.util.Formatter; + +import org.apache.log4j.Logger; + +import com.cloud.utils.NumbersUtil; + +/** + * copied from the public domain utility from John Burkard. + * @author Johann Burkard + * @version 2.1.3 + **/ +public class MacAddress { + private static final Logger s_logger = Logger.getLogger(MacAddress.class); + private long _addr = 0; + + protected MacAddress() { + } + + public MacAddress(long addr) { + _addr = addr; + } + + public long toLong() { + return _addr; + } + + public byte[] toByteArray() { + byte[] bytes = new byte[6]; + bytes[0] = (byte)((_addr >> 40) & 0xff); + bytes[1] = (byte)((_addr >> 32) & 0xff); + bytes[2] = (byte)((_addr >> 24) & 0xff); + bytes[3] = (byte)((_addr >> 16) & 0xff); + bytes[4] = (byte)((_addr >> 8) & 0xff); + bytes[5] = (byte)((_addr >> 0) & 0xff); + return bytes; + } + + public String toString(String separator) { + StringBuilder buff = new StringBuilder(); + Formatter formatter = new Formatter(buff); + formatter.format("%02x%s%02x%s%02x%s%02x%s%02x%s%02x", _addr >> 40 & 0xff, separator, _addr >> 32 & 0xff, separator, _addr >> 24 & 0xff, separator, + _addr >> 16 & 0xff, separator, _addr >> 8 & 0xff, separator, _addr & 0xff); + return buff.toString(); + + /* + + String str = Long.toHexString(_addr); + + for (int i = str.length() - 1; i >= 0; i--) { + buff.append(str.charAt(i)); + if (separator != null && (str.length() - i) % 2 == 0) { + buff.append(separator); + } + } + return buff.reverse().toString(); + */ + } + + @Override + public String toString() { + return toString(":"); + } + + private static MacAddress s_address; + static { + String macAddress = null; + + Process p = null; + BufferedReader in = null; + + try { + String osname = System.getProperty("os.name"); + + if (osname.startsWith("Windows")) { + p = Runtime.getRuntime().exec(new String[] {"ipconfig", "/all"}, null); + } else if (osname.startsWith("Solaris") || osname.startsWith("SunOS")) { + // Solaris code must appear before the generic code + String hostName = MacAddress.getFirstLineOfCommand(new String[] {"uname", "-n"}); + if (hostName != null) { + p = Runtime.getRuntime().exec(new String[] {"/usr/sbin/arp", hostName}, null); + } + } else if (new File("/usr/sbin/lanscan").exists()) { + p = Runtime.getRuntime().exec(new String[] {"/usr/sbin/lanscan"}, null); + } else if (new File("/sbin/ifconfig").exists()) { + p = Runtime.getRuntime().exec(new String[] {"/sbin/ifconfig", "-a"}, null); + } + + if (p != null) { + in = new BufferedReader(new InputStreamReader(p.getInputStream()), 128); + String l = null; + while ((l = in.readLine()) != null) { + macAddress = MacAddress.parse(l); + if (macAddress != null) { + short parsedShortMacAddress = MacAddress.parseShort(macAddress); + if (parsedShortMacAddress != 0xff && parsedShortMacAddress != 0x00) + break; + } + macAddress = null; + } + } + + } catch (SecurityException ex) { + s_logger.info("[ignored] security exception in static initializer of MacAddress", ex); + } catch (IOException ex) { + s_logger.info("[ignored] io exception in static initializer of MacAddress"); + } finally { + if (p != null) { + closeAutoCloseable(in, "closing init process input stream"); + closeAutoCloseable(p.getErrorStream(), "closing init process error output stream"); + closeAutoCloseable(p.getOutputStream(), "closing init process std output stream"); + p.destroy(); + } + } + + long clockSeqAndNode = 0; + + if (macAddress != null) { + if (macAddress.indexOf(':') != -1) { + clockSeqAndNode |= MacAddress.parseLong(macAddress); + } else if (macAddress.startsWith("0x")) { + clockSeqAndNode |= MacAddress.parseLong(macAddress.substring(2)); + } + } else { + try { + byte[] local = InetAddress.getLocalHost().getAddress(); + clockSeqAndNode |= (local[0] << 24) & 0xFF000000L; + clockSeqAndNode |= (local[1] << 16) & 0xFF0000; + clockSeqAndNode |= (local[2] << 8) & 0xFF00; + clockSeqAndNode |= local[3] & 0xFF; + } catch (UnknownHostException ex) { + clockSeqAndNode |= (long)(Math.random() * 0x7FFFFFFF); + } + } + + s_address = new MacAddress(clockSeqAndNode); + } + + public static MacAddress getMacAddress() { + return s_address; + } + + private static String getFirstLineOfCommand(String[] commands) throws IOException { + + Process p = null; + BufferedReader reader = null; + + try { + p = Runtime.getRuntime().exec(commands); + reader = new BufferedReader(new InputStreamReader(p.getInputStream()), 128); + + return reader.readLine(); + } finally { + if (p != null) { + closeAutoCloseable(reader, "closing process input stream"); + closeAutoCloseable(p.getErrorStream(), "closing process error output stream"); + closeAutoCloseable(p.getOutputStream(), "closing process std output stream"); + p.destroy(); + } + } + + } + + /** + * The MAC address parser attempts to find the following patterns: + *
    + *
  • .{1,2}:.{1,2}:.{1,2}:.{1,2}:.{1,2}:.{1,2}
  • + *
  • .{1,2}-.{1,2}-.{1,2}-.{1,2}-.{1,2}-.{1,2}
  • + *
+ * + * This is copied from the author below. The author encouraged copying + * it. + * + */ + static String parse(String in) { + + // lanscan + + int hexStart = in.indexOf("0x"); + if (hexStart != -1) { + int hexEnd = in.indexOf(' ', hexStart); + if (hexEnd != -1) { + return in.substring(hexStart, hexEnd); + } + } + + int octets = 0; + int lastIndex, old, end; + + if (in.indexOf('-') > -1) { + in = in.replace('-', ':'); + } + + lastIndex = in.lastIndexOf(':'); + + if (lastIndex > in.length() - 2) + return null; + + end = Math.min(in.length(), lastIndex + 3); + + ++octets; + old = lastIndex; + while (octets != 5 && lastIndex != -1 && lastIndex > 1) { + lastIndex = in.lastIndexOf(':', --lastIndex); + if (old - lastIndex == 3 || old - lastIndex == 2) { + ++octets; + old = lastIndex; + } + } + + if (octets == 5 && lastIndex > 1) { + return in.substring(lastIndex - 2, end).trim(); + } + return null; + } + + public static void main(String[] args) { + MacAddress addr = MacAddress.getMacAddress(); + System.out.println("addr in integer is " + addr.toLong()); + System.out.println("addr in bytes is " + NumbersUtil.bytesToString(addr.toByteArray(), 0, addr.toByteArray().length)); + System.out.println("addr in char is " + addr.toString(":")); + } + + /** + * Parses a long from a hex encoded number. This method will skip + * all characters that are not 0-9 and a-f (the String is lower cased first). + * Returns 0 if the String does not contain any interesting characters. + * + * @param s the String to extract a long from, may not be null + * @return a long + * @throws NullPointerException if the String is null + */ + public static long parseLong(String s) throws NullPointerException { + s = s.toLowerCase(); + long out = 0; + byte shifts = 0; + char c; + for (int i = 0; i < s.length() && shifts < 16; i++) { + c = s.charAt(i); + if ((c > 47) && (c < 58)) { + out <<= 4; + ++shifts; + out |= c - 48; + } else if ((c > 96) && (c < 103)) { + ++shifts; + out <<= 4; + out |= c - 87; + } + } + return out; + } + + /** + * Parses an int from a hex encoded number. This method will skip + * all characters that are not 0-9 and a-f (the String is lower cased first). + * Returns 0 if the String does not contain any interesting characters. + * + * @param s the String to extract an int from, may not be null + * @return an int + * @throws NullPointerException if the String is null + */ + public static int parseInt(String s) throws NullPointerException { + s = s.toLowerCase(); + int out = 0; + byte shifts = 0; + char c; + for (int i = 0; i < s.length() && shifts < 8; i++) { + c = s.charAt(i); + if ((c > 47) && (c < 58)) { + out <<= 4; + ++shifts; + out |= c - 48; + } else if ((c > 96) && (c < 103)) { + ++shifts; + out <<= 4; + out |= c - 87; + } + } + return out; + } + + /** + * Parses a short from a hex encoded number. This method will skip + * all characters that are not 0-9 and a-f (the String is lower cased first). + * Returns 0 if the String does not contain any interesting characters. + * + * @param s the String to extract a short from, may not be null + * @return a short + * @throws NullPointerException if the String is null + */ + public static short parseShort(String s) throws NullPointerException { + s = s.toLowerCase(); + short out = 0; + byte shifts = 0; + char c; + for (int i = 0; i < s.length() && shifts < 4; i++) { + c = s.charAt(i); + if ((c > 47) && (c < 58)) { + out <<= 4; + ++shifts; + out |= c - 48; + } else if ((c > 96) && (c < 103)) { + ++shifts; + out <<= 4; + out |= c - 87; + } + } + return out; + } + + /** + * Parses a byte from a hex encoded number. This method will skip + * all characters that are not 0-9 and a-f (the String is lower cased first). + * Returns 0 if the String does not contain any interesting characters. + * + * @param s the String to extract a byte from, may not be null + * @return a byte + * @throws NullPointerException if the String is null + */ + public static byte parseByte(String s) throws NullPointerException { + s = s.toLowerCase(); + byte out = 0; + byte shifts = 0; + char c; + for (int i = 0; i < s.length() && shifts < 2; i++) { + c = s.charAt(i); + if ((c > 47) && (c < 58)) { + out <<= 4; + ++shifts; + out |= c - 48; + } else if ((c > 96) && (c < 103)) { + ++shifts; + out <<= 4; + out |= c - 87; + } + } + return out; + } +}